aes_cbc.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package seclib2
  15. import (
  16. "bytes"
  17. "crypto/aes"
  18. "crypto/cipher"
  19. "crypto/rand"
  20. "encoding/base64"
  21. "fmt"
  22. "github.com/tjfoc/gmsm/sm4"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/util/seclib"
  25. )
  26. type TSymEncAlg string
  27. const (
  28. SYM_ENC_ALG_AES_256 = TSymEncAlg("aes-256")
  29. SYM_ENC_ALG_SM4_128 = TSymEncAlg("sm4")
  30. )
  31. type SSymEncAlg struct {
  32. name TSymEncAlg
  33. blockSize int
  34. newCipher func(key []byte) (cipher.Block, error)
  35. keySize int
  36. }
  37. var (
  38. AES_256 = SSymEncAlg{
  39. name: SYM_ENC_ALG_AES_256,
  40. blockSize: aes.BlockSize,
  41. newCipher: aes.NewCipher,
  42. keySize: 32,
  43. }
  44. SM4_128 = SSymEncAlg{
  45. name: SYM_ENC_ALG_SM4_128,
  46. blockSize: sm4.BlockSize,
  47. newCipher: sm4.NewCipher,
  48. keySize: 16,
  49. }
  50. )
  51. func Alg(alg TSymEncAlg) SSymEncAlg {
  52. switch alg {
  53. case SYM_ENC_ALG_SM4_128:
  54. return SM4_128
  55. case SYM_ENC_ALG_AES_256:
  56. return AES_256
  57. default:
  58. return AES_256
  59. }
  60. }
  61. // AES-256-CBC
  62. // key: 32bytes=256bites
  63. func (alg SSymEncAlg) CbcEncodeIV(content []byte, encryptionKey []byte, IV []byte) ([]byte, error) {
  64. bPlaintext, err := pkcs7pad(content, alg.blockSize)
  65. if err != nil {
  66. return nil, errors.Wrap(err, "pkcs7pad")
  67. }
  68. block, err := alg.newCipher(alg.normalizeKey(encryptionKey))
  69. if err != nil {
  70. return nil, errors.Wrap(err, "newCipher")
  71. }
  72. if len(IV) == 0 {
  73. IV, _ = GenerateRandomBytes(block.BlockSize())
  74. }
  75. ciphertext := make([]byte, block.BlockSize()+len(bPlaintext))
  76. copy(ciphertext, IV)
  77. mode := cipher.NewCBCEncrypter(block, IV)
  78. mode.CryptBlocks(ciphertext[block.BlockSize():], bPlaintext)
  79. return ciphertext, nil
  80. }
  81. func (alg SSymEncAlg) CbcEncode(content []byte, encryptionKey []byte) ([]byte, error) {
  82. return alg.CbcEncodeIV(content, encryptionKey, nil)
  83. }
  84. func (alg SSymEncAlg) normalizeKey(encKey []byte) []byte {
  85. for len(encKey) < alg.keySize {
  86. encKey = append(encKey, '0')
  87. }
  88. if len(encKey) > alg.keySize {
  89. encKey = encKey[:alg.keySize]
  90. }
  91. return encKey
  92. }
  93. func (alg SSymEncAlg) CbcDecode(cipherText []byte, encryptionKey []byte) ([]byte, error) {
  94. block, err := alg.newCipher(alg.normalizeKey(encryptionKey))
  95. if err != nil {
  96. return nil, errors.Wrap(err, "newCipher")
  97. }
  98. if len(cipherText) < block.BlockSize() {
  99. return nil, errors.Wrap(errors.ErrInvalidStatus, "not a encrypted text")
  100. }
  101. mode := cipher.NewCBCDecrypter(block, cipherText[:block.BlockSize()])
  102. cipherText = cipherText[block.BlockSize():]
  103. mode.CryptBlocks(cipherText, cipherText)
  104. return pkcs7strip(cipherText, alg.blockSize)
  105. }
  106. func (alg SSymEncAlg) CbcEncodeBase64(content []byte, encryptionKey []byte) (string, error) {
  107. bSecret, err := alg.CbcEncode(content, encryptionKey)
  108. if err != nil {
  109. return "", errors.Wrap(err, "Aes256CbcEncode")
  110. }
  111. secret := base64.StdEncoding.EncodeToString(bSecret)
  112. return secret, nil
  113. }
  114. func (alg SSymEncAlg) CbcDecodeBase64(cipherText string, encryptionKey []byte) ([]byte, error) {
  115. bCipher, err := base64.StdEncoding.DecodeString(cipherText)
  116. if err != nil {
  117. return nil, errors.Wrap(err, "base64.StdEncoding.DecodeString cipher")
  118. }
  119. return alg.CbcDecode(bCipher, encryptionKey)
  120. }
  121. func (alg SSymEncAlg) GenerateKey() string {
  122. return seclib.RandomPassword(alg.keySize)
  123. }
  124. func (alg SSymEncAlg) Name() TSymEncAlg {
  125. return alg.name
  126. }
  127. // pkcs7strip remove pkcs7 padding
  128. func pkcs7strip(data []byte, blockSize int) ([]byte, error) {
  129. length := len(data)
  130. if length == 0 {
  131. return nil, errors.Error("pkcs7: Data is empty")
  132. }
  133. if length%blockSize != 0 {
  134. return nil, errors.Error("pkcs7: Data is not block-aligned")
  135. }
  136. padLen := int(data[length-1])
  137. ref := bytes.Repeat([]byte{byte(padLen)}, padLen)
  138. if padLen > blockSize || padLen == 0 || !bytes.HasSuffix(data, ref) {
  139. return nil, errors.Error("pkcs7: Invalid padding")
  140. }
  141. return data[:length-padLen], nil
  142. }
  143. // pkcs7pad add pkcs7 padding
  144. func pkcs7pad(data []byte, blockSize int) ([]byte, error) {
  145. if blockSize < 0 || blockSize > 256 {
  146. return nil, errors.Error(fmt.Sprintf("pkcs7: Invalid block size %d", blockSize))
  147. } else {
  148. padLen := blockSize - len(data)%blockSize
  149. padding := bytes.Repeat([]byte{byte(padLen)}, padLen)
  150. return append(data, padding...), nil
  151. }
  152. }
  153. func GenerateRandomBytes(n int) ([]byte, error) {
  154. b := make([]byte, n)
  155. _, err := rand.Read(b)
  156. if err != nil {
  157. return nil, err
  158. }
  159. return b, nil
  160. }