fernet.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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 fernetool
  15. import (
  16. "crypto/sha1"
  17. "encoding/base64"
  18. "encoding/hex"
  19. "fmt"
  20. "io/ioutil"
  21. "path/filepath"
  22. "time"
  23. "github.com/fernet/fernet-go"
  24. "github.com/pkg/errors"
  25. "yunion.io/x/onecloud/pkg/util/fileutils2"
  26. )
  27. type SFernetKeyManager struct {
  28. keys []*fernet.Key
  29. }
  30. func (m *SFernetKeyManager) InitEmpty() error {
  31. src := [32]byte{}
  32. dst := base64.URLEncoding.EncodeToString(src[:])
  33. emptyKey, err := fernet.DecodeKey(dst)
  34. if err != nil {
  35. return errors.WithMessage(err, "InitEmpty with fernet.DecodeKey")
  36. }
  37. m.keys = []*fernet.Key{emptyKey}
  38. return nil
  39. }
  40. func (m *SFernetKeyManager) PrimaryKeyHash() string {
  41. if len(m.keys) == 0 {
  42. return ""
  43. }
  44. dst := m.keys[0].Encode()
  45. sum := sha1.Sum([]byte(dst))
  46. return hex.EncodeToString(sum[:])
  47. }
  48. func (m *SFernetKeyManager) SetKeys(keys []*fernet.Key) {
  49. m.keys = keys
  50. }
  51. func (m *SFernetKeyManager) LoadKeys(path string) error {
  52. filesInfos, err := ioutil.ReadDir(path)
  53. if err != nil {
  54. return err
  55. }
  56. keyStrs := make([]string, 0)
  57. for i := range filesInfos {
  58. fn := filepath.Join(path, filesInfos[i].Name())
  59. keyBytes, err := ioutil.ReadFile(fn)
  60. if err != nil {
  61. return err
  62. }
  63. keyStrs = append(keyStrs, string(keyBytes))
  64. }
  65. if len(keyStrs) == 0 {
  66. return fmt.Errorf("empty fernet keys")
  67. }
  68. keys, err := fernet.DecodeKeys(keyStrs...)
  69. if err != nil {
  70. return err
  71. }
  72. m.keys = keys
  73. return nil
  74. }
  75. func (m *SFernetKeyManager) Decrypt(tok []byte) []byte {
  76. return m.VerifyAndDecrypt(tok, 0)
  77. }
  78. func (m *SFernetKeyManager) VerifyAndDecrypt(tok []byte, ttl time.Duration) []byte {
  79. modReturned := len(tok) % 4
  80. if modReturned > 0 {
  81. for i := 0; i < 4-modReturned; i += 1 {
  82. tok = append(tok, '=')
  83. }
  84. }
  85. return fernet.VerifyAndDecrypt(tok, ttl, m.keys)
  86. }
  87. func (m *SFernetKeyManager) InitKeys(path string, cnt int) error {
  88. m.keys = make([]*fernet.Key, cnt)
  89. for i := 0; i < cnt; i += 1 {
  90. key := fernet.Key{}
  91. err := key.Generate()
  92. if err != nil {
  93. return err
  94. }
  95. if len(path) > 0 && fileutils2.IsDir(path) {
  96. fn := filepath.Join(path, fmt.Sprintf("%d", i))
  97. err = fileutils2.FileSetContents(fn, key.Encode())
  98. if err != nil {
  99. return err
  100. }
  101. }
  102. m.keys[i] = &key
  103. }
  104. return nil
  105. }
  106. func (m *SFernetKeyManager) Encrypt(msg []byte) ([]byte, error) {
  107. hash := 0
  108. for i := 0; i < len(msg) && i < 10; i += 1 {
  109. hash += int(msg[i])
  110. }
  111. idx := hash % len(m.keys)
  112. tok, err := fernet.EncryptAndSign([]byte(msg), m.keys[idx])
  113. if err != nil {
  114. return nil, err
  115. }
  116. endIdx := len(tok)
  117. for endIdx >= 0 && tok[endIdx-1] == '=' {
  118. endIdx -= 1
  119. }
  120. return tok[:endIdx], nil
  121. }