aes.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. "crypto/aes"
  17. "crypto/cipher"
  18. "crypto/rand"
  19. "fmt"
  20. "io"
  21. )
  22. // https://stackoverflow.com/questions/23897809/different-results-in-go-and-pycrypto-when-using-aes-cfb
  23. // CFB stream with 8 bit segment size
  24. // See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
  25. type cfb8 struct {
  26. b cipher.Block
  27. blockSize int
  28. in []byte
  29. out []byte
  30. decrypt bool
  31. }
  32. func (x *cfb8) XORKeyStream(dst, src []byte) {
  33. for i := range src {
  34. x.b.Encrypt(x.out, x.in)
  35. copy(x.in[:x.blockSize-1], x.in[1:])
  36. if x.decrypt {
  37. x.in[x.blockSize-1] = src[i]
  38. }
  39. dst[i] = src[i] ^ x.out[0]
  40. if !x.decrypt {
  41. x.in[x.blockSize-1] = dst[i]
  42. }
  43. }
  44. }
  45. // NewCFB8Encrypter returns a Stream which encrypts with cipher feedback mode
  46. // (segment size = 8), using the given Block. The iv must be the same length as
  47. // the Block's block size.
  48. func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream {
  49. return newCFB8(block, iv, false)
  50. }
  51. // NewCFB8Decrypter returns a Stream which decrypts with cipher feedback mode
  52. // (segment size = 8), using the given Block. The iv must be the same length as
  53. // the Block's block size.
  54. func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream {
  55. return newCFB8(block, iv, true)
  56. }
  57. func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
  58. blockSize := block.BlockSize()
  59. if len(iv) != blockSize {
  60. // stack trace will indicate whether it was de or encryption
  61. panic("cipher.newCFB: IV length must equal block size")
  62. }
  63. x := &cfb8{
  64. b: block,
  65. blockSize: blockSize,
  66. out: make([]byte, blockSize),
  67. in: make([]byte, blockSize),
  68. decrypt: decrypt,
  69. }
  70. copy(x.in, iv)
  71. return x
  72. }
  73. func toAESKey(k []byte) []byte {
  74. if len(k) > 32 {
  75. return k[0:32]
  76. } else {
  77. for len(k) < 32 {
  78. k = append(k, '$')
  79. }
  80. return k
  81. }
  82. }
  83. func decryptAES(k, secret []byte) ([]byte, error) {
  84. block, err := aes.NewCipher(toAESKey(k))
  85. if err != nil {
  86. return nil, err
  87. }
  88. if len(secret) < aes.BlockSize {
  89. return nil, fmt.Errorf("ciphertext too short")
  90. }
  91. iv := secret[:aes.BlockSize]
  92. ciphertext := secret[aes.BlockSize:]
  93. stream := newCFB8Decrypter(block, iv)
  94. stream.XORKeyStream(ciphertext, ciphertext)
  95. return ciphertext, nil
  96. }
  97. func encryptAES(k, msg []byte) ([]byte, error) {
  98. block, err := aes.NewCipher(toAESKey(k))
  99. if err != nil {
  100. return nil, err
  101. }
  102. cipherText := make([]byte, aes.BlockSize+len(msg))
  103. iv := cipherText[:aes.BlockSize]
  104. if _, err = io.ReadFull(rand.Reader, iv); err != nil {
  105. return nil, err
  106. }
  107. stream := newCFB8Encrypter(block, iv)
  108. stream.XORKeyStream(cipherText[aes.BlockSize:], msg)
  109. return cipherText, nil
  110. }