github.com/go-board/x-go@v0.1.2-0.20220610024734-db1323f6cb15/xcrypt/aes.go (about)

     1  package xcrypt
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"encoding/hex"
     8  	"errors"
     9  )
    10  
    11  const AesCipherKeySize = 32 // aes key size, 256 bit
    12  
    13  // AesEncryptRaw encrypt original `data` with `key` and initializer vector `iv`
    14  // iv should have at least `aes.BlockSize` length
    15  func AesEncryptRaw(data []byte, key []byte, iv []byte) ([]byte, error) {
    16  	if len(key) < AesCipherKeySize {
    17  		return nil, errors.New("err: key too short, length less than 32")
    18  	}
    19  	key = key[:AesCipherKeySize]
    20  	if len(iv) < aes.BlockSize {
    21  		return nil, errors.New("err: cipher iv too short, length less than 16")
    22  	}
    23  	iv = iv[:aes.BlockSize]
    24  	block, _ := aes.NewCipher(key) // ignore not reachable error
    25  	blockMode := cipher.NewCBCEncrypter(block, iv)
    26  	encodedData := pkcs5Padding(data, block.BlockSize())
    27  	encryptedData := make([]byte, len(encodedData))
    28  	blockMode.CryptBlocks(encryptedData, encodedData)
    29  	dst := make([]byte, hex.EncodedLen(len(encryptedData)))
    30  	hex.Encode(dst, encryptedData)
    31  	return dst, nil
    32  }
    33  
    34  // AesDecryptRaw decrypt original `data` with `key` and initializer vector `iv`
    35  // iv should have at least `aes.BlockSize` length
    36  func AesDecryptRaw(data []byte, key []byte, iv []byte) ([]byte, error) {
    37  	if len(key) < AesCipherKeySize {
    38  		return nil, errors.New("err: key too short, length less than 32")
    39  	}
    40  	key = key[:AesCipherKeySize]
    41  	if len(iv) < aes.BlockSize {
    42  		return nil, errors.New("err: cipher iv too short, length less than 16")
    43  	}
    44  	iv = iv[:aes.BlockSize]
    45  	decodedLen := hex.DecodedLen(len(data))
    46  	decodedData := make([]byte, decodedLen)
    47  	if _, err := hex.Decode(decodedData, data); err != nil {
    48  		return nil, err
    49  	}
    50  	block, _ := aes.NewCipher(key) // ignore not reachable error
    51  	blockMode := cipher.NewCBCDecrypter(block, iv)
    52  	blockMode.CryptBlocks(decodedData, decodedData)
    53  	return pkcs5UnPadding(decodedData[:decodedLen]), nil
    54  }
    55  
    56  func pkcs5Padding(cipherText []byte, blockSize int) []byte {
    57  	padding := blockSize - len(cipherText)%blockSize
    58  	padText := bytes.Repeat([]byte{byte(padding)}, padding)
    59  	return append(cipherText, padText...)
    60  }
    61  
    62  func pkcs5UnPadding(origData []byte) []byte {
    63  	length := len(origData)
    64  	unpadding := int(origData[length-1])
    65  	return origData[:(length - unpadding)]
    66  }