gaes.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. "github.com/gogf/gf/errors/gcode"
  13. "github.com/gogf/gf/errors/gerror"
  14. )
  15. var (
  16. // IVDefaultValue is the default value for IV.
  17. // This can be changed globally.
  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. return nil, err
  35. }
  36. blockSize := block.BlockSize()
  37. plainText = PKCS5Padding(plainText, blockSize)
  38. ivValue := ([]byte)(nil)
  39. if len(iv) > 0 {
  40. ivValue = iv[0]
  41. } else {
  42. ivValue = []byte(IVDefaultValue)
  43. }
  44. blockMode := cipher.NewCBCEncrypter(block, ivValue)
  45. cipherText := make([]byte, len(plainText))
  46. blockMode.CryptBlocks(cipherText, plainText)
  47. return cipherText, nil
  48. }
  49. // DecryptCBC decrypts <cipherText> using CBC mode.
  50. // Note that the key must be 16/24/32 bit length.
  51. // The parameter <iv> initialization vector is unnecessary.
  52. func DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
  53. block, err := aes.NewCipher(key)
  54. if err != nil {
  55. return nil, err
  56. }
  57. blockSize := block.BlockSize()
  58. if len(cipherText) < blockSize {
  59. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short")
  60. }
  61. ivValue := ([]byte)(nil)
  62. if len(iv) > 0 {
  63. ivValue = iv[0]
  64. } else {
  65. ivValue = []byte(IVDefaultValue)
  66. }
  67. if len(cipherText)%blockSize != 0 {
  68. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText is not a multiple of the block size")
  69. }
  70. blockModel := cipher.NewCBCDecrypter(block, ivValue)
  71. plainText := make([]byte, len(cipherText))
  72. blockModel.CryptBlocks(plainText, cipherText)
  73. plainText, e := PKCS5UnPadding(plainText, blockSize)
  74. if e != nil {
  75. return nil, e
  76. }
  77. return plainText, nil
  78. }
  79. func PKCS5Padding(src []byte, blockSize int) []byte {
  80. padding := blockSize - len(src)%blockSize
  81. padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  82. return append(src, padtext...)
  83. }
  84. func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) {
  85. length := len(src)
  86. if blockSize <= 0 {
  87. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid blocklen")
  88. }
  89. if length%blockSize != 0 || length == 0 {
  90. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid data len")
  91. }
  92. unpadding := int(src[length-1])
  93. if unpadding > blockSize || unpadding == 0 {
  94. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding")
  95. }
  96. padding := src[length-unpadding:]
  97. for i := 0; i < unpadding; i++ {
  98. if padding[i] != byte(unpadding) {
  99. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding")
  100. }
  101. }
  102. return src[:(length - unpadding)], nil
  103. }
  104. // EncryptCFB encrypts <plainText> using CFB mode.
  105. // Note that the key must be 16/24/32 bit length.
  106. // The parameter <iv> initialization vector is unnecessary.
  107. func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) {
  108. block, err := aes.NewCipher(key)
  109. if err != nil {
  110. return nil, err
  111. }
  112. blockSize := block.BlockSize()
  113. plainText, *padding = ZeroPadding(plainText, blockSize)
  114. ivValue := ([]byte)(nil)
  115. if len(iv) > 0 {
  116. ivValue = iv[0]
  117. } else {
  118. ivValue = []byte(IVDefaultValue)
  119. }
  120. stream := cipher.NewCFBEncrypter(block, ivValue)
  121. cipherText := make([]byte, len(plainText))
  122. stream.XORKeyStream(cipherText, plainText)
  123. return cipherText, nil
  124. }
  125. // DecryptCFB decrypts <plainText> using CFB mode.
  126. // Note that the key must be 16/24/32 bit length.
  127. // The parameter <iv> initialization vector is unnecessary.
  128. func DecryptCFB(cipherText []byte, key []byte, unPadding int, iv ...[]byte) ([]byte, error) {
  129. block, err := aes.NewCipher(key)
  130. if err != nil {
  131. return nil, err
  132. }
  133. if len(cipherText) < aes.BlockSize {
  134. return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short")
  135. }
  136. ivValue := ([]byte)(nil)
  137. if len(iv) > 0 {
  138. ivValue = iv[0]
  139. } else {
  140. ivValue = []byte(IVDefaultValue)
  141. }
  142. stream := cipher.NewCFBDecrypter(block, ivValue)
  143. plainText := make([]byte, len(cipherText))
  144. stream.XORKeyStream(plainText, cipherText)
  145. plainText = ZeroUnPadding(plainText, unPadding)
  146. return plainText, nil
  147. }
  148. func ZeroPadding(cipherText []byte, blockSize int) ([]byte, int) {
  149. padding := blockSize - len(cipherText)%blockSize
  150. padText := bytes.Repeat([]byte{byte(0)}, padding)
  151. return append(cipherText, padText...), padding
  152. }
  153. func ZeroUnPadding(plaintext []byte, unPadding int) []byte {
  154. length := len(plaintext)
  155. return plaintext[:(length - unPadding)]
  156. }