gaes.go 6.4 KB

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