gaes.go 4.9 KB

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