github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/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 "fmt" 15 16 "github.com/wangyougui/gf/v2/errors/gcode" 17 "github.com/wangyougui/gf/v2/errors/gerror" 18 ) 19 20 const ( 21 // IVDefaultValue is the default value for IV. 22 IVDefaultValue = "I Love Go Frame!" 23 ) 24 25 // Encrypt is alias of EncryptCBC. 26 func Encrypt(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) { 27 return EncryptCBC(plainText, key, iv...) 28 } 29 30 // Decrypt is alias of DecryptCBC. 31 func Decrypt(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) { 32 return DecryptCBC(cipherText, key, iv...) 33 } 34 35 // EncryptCBC encrypts `plainText` using CBC mode. 36 // Note that the key must be 16/24/32 bit length. 37 // The parameter `iv` initialization vector is unnecessary. 38 func EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) { 39 block, err := aes.NewCipher(key) 40 if err != nil { 41 err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key) 42 return nil, err 43 } 44 blockSize := block.BlockSize() 45 plainText = PKCS7Padding(plainText, blockSize) 46 ivValue := ([]byte)(nil) 47 if len(iv) > 0 { 48 ivValue = iv[0] 49 } else { 50 ivValue = []byte(IVDefaultValue) 51 } 52 blockMode := cipher.NewCBCEncrypter(block, ivValue) 53 cipherText := make([]byte, len(plainText)) 54 blockMode.CryptBlocks(cipherText, plainText) 55 56 return cipherText, nil 57 } 58 59 // DecryptCBC decrypts `cipherText` using CBC mode. 60 // Note that the key must be 16/24/32 bit length. 61 // The parameter `iv` initialization vector is unnecessary. 62 func DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) { 63 block, err := aes.NewCipher(key) 64 if err != nil { 65 err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key) 66 return nil, err 67 } 68 blockSize := block.BlockSize() 69 if len(cipherText) < blockSize { 70 return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short") 71 } 72 ivValue := ([]byte)(nil) 73 if len(iv) > 0 { 74 ivValue = iv[0] 75 } else { 76 ivValue = []byte(IVDefaultValue) 77 } 78 if len(cipherText)%blockSize != 0 { 79 return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText is not a multiple of the block size") 80 } 81 blockModel := cipher.NewCBCDecrypter(block, ivValue) 82 plainText := make([]byte, len(cipherText)) 83 blockModel.CryptBlocks(plainText, cipherText) 84 plainText, e := PKCS7UnPadding(plainText, blockSize) 85 if e != nil { 86 return nil, e 87 } 88 return plainText, nil 89 } 90 91 // PKCS5Padding applies PKCS#5 padding to the source byte slice to match the given block size. 92 // 93 // If the block size is not provided, it defaults to 8. 94 func PKCS5Padding(src []byte, blockSize ...int) []byte { 95 blockSizeTemp := 8 96 if len(blockSize) > 0 { 97 blockSizeTemp = blockSize[0] 98 } 99 return PKCS7Padding(src, blockSizeTemp) 100 } 101 102 // PKCS5UnPadding removes PKCS#5 padding from the source byte slice based on the given block size. 103 // 104 // If the block size is not provided, it defaults to 8. 105 func PKCS5UnPadding(src []byte, blockSize ...int) ([]byte, error) { 106 blockSizeTemp := 8 107 if len(blockSize) > 0 { 108 blockSizeTemp = blockSize[0] 109 } 110 return PKCS7UnPadding(src, blockSizeTemp) 111 } 112 113 // PKCS7Padding applies PKCS#7 padding to the source byte slice to match the given block size. 114 func PKCS7Padding(src []byte, blockSize int) []byte { 115 padding := blockSize - len(src)%blockSize 116 padtext := bytes.Repeat([]byte{byte(padding)}, padding) 117 return append(src, padtext...) 118 } 119 120 // PKCS7UnPadding removes PKCS#7 padding from the source byte slice based on the given block size. 121 func PKCS7UnPadding(src []byte, blockSize int) ([]byte, error) { 122 length := len(src) 123 if blockSize <= 0 { 124 return nil, gerror.NewCode(gcode.CodeInvalidParameter, fmt.Sprintf("invalid blockSize: %d", blockSize)) 125 } 126 127 if length%blockSize != 0 || length == 0 { 128 return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid data len") 129 } 130 131 unpadding := int(src[length-1]) 132 if unpadding > blockSize || unpadding == 0 { 133 return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid unpadding") 134 } 135 136 padding := src[length-unpadding:] 137 for i := 0; i < unpadding; i++ { 138 if padding[i] != byte(unpadding) { 139 return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding") 140 } 141 } 142 143 return src[:(length - unpadding)], nil 144 } 145 146 // EncryptCFB encrypts `plainText` using CFB mode. 147 // Note that the key must be 16/24/32 bit length. 148 // The parameter `iv` initialization vector is unnecessary. 149 func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) { 150 block, err := aes.NewCipher(key) 151 if err != nil { 152 err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key) 153 return nil, err 154 } 155 blockSize := block.BlockSize() 156 plainText, *padding = ZeroPadding(plainText, blockSize) 157 ivValue := ([]byte)(nil) 158 if len(iv) > 0 { 159 ivValue = iv[0] 160 } else { 161 ivValue = []byte(IVDefaultValue) 162 } 163 stream := cipher.NewCFBEncrypter(block, ivValue) 164 cipherText := make([]byte, len(plainText)) 165 stream.XORKeyStream(cipherText, plainText) 166 return cipherText, nil 167 } 168 169 // DecryptCFB decrypts `plainText` using CFB mode. 170 // Note that the key must be 16/24/32 bit length. 171 // The parameter `iv` initialization vector is unnecessary. 172 func DecryptCFB(cipherText []byte, key []byte, unPadding int, iv ...[]byte) ([]byte, error) { 173 block, err := aes.NewCipher(key) 174 if err != nil { 175 err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key) 176 return nil, err 177 } 178 if len(cipherText) < aes.BlockSize { 179 return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short") 180 } 181 ivValue := ([]byte)(nil) 182 if len(iv) > 0 { 183 ivValue = iv[0] 184 } else { 185 ivValue = []byte(IVDefaultValue) 186 } 187 stream := cipher.NewCFBDecrypter(block, ivValue) 188 plainText := make([]byte, len(cipherText)) 189 stream.XORKeyStream(plainText, cipherText) 190 plainText = ZeroUnPadding(plainText, unPadding) 191 return plainText, nil 192 } 193 194 func ZeroPadding(cipherText []byte, blockSize int) ([]byte, int) { 195 padding := blockSize - len(cipherText)%blockSize 196 padText := bytes.Repeat([]byte{byte(0)}, padding) 197 return append(cipherText, padText...), padding 198 } 199 200 func ZeroUnPadding(plaintext []byte, unPadding int) []byte { 201 length := len(plaintext) 202 return plaintext[:(length - unPadding)] 203 }