Нема описа
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package crypto
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "encoding/base64"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "strings"
  11. )
  12. // CryptoService 加密服务结构体
  13. type CryptoService struct {
  14. key []byte
  15. prefix string // 加密文本前缀,用于识别是否已加密
  16. }
  17. // NewCryptoService 创建加密服务
  18. func NewCryptoService(key string) (*CryptoService, error) {
  19. keyBytes := []byte(key)
  20. // 如果密钥长度不足,使用PBKDF2派生密钥
  21. if len(keyBytes) < 32 {
  22. derivedKey, err := deriveKey(keyBytes, 32)
  23. if err != nil {
  24. return nil, err
  25. }
  26. keyBytes = derivedKey
  27. } else if len(keyBytes) > 32 {
  28. keyBytes = keyBytes[:32] // 截取前32字节
  29. }
  30. return &CryptoService{
  31. key: keyBytes,
  32. prefix: "ENC::", // 加密文本前缀
  33. }, nil
  34. }
  35. // deriveKey 使用PBKDF2派生密钥
  36. func deriveKey(password []byte, keyLen int) ([]byte, error) {
  37. // 这里简化实现,实际应该使用crypto/sha256和更复杂的盐
  38. // 为了简单示例,使用固定盐(生产环境应该使用随机盐)
  39. salt := []byte("fixed-salt-for-demo")
  40. hash := make([]byte, keyLen)
  41. for i := 0; i < keyLen; i++ {
  42. if i < len(password) {
  43. hash[i] = password[i] ^ salt[i%len(salt)]
  44. } else {
  45. hash[i] = salt[i%len(salt)]
  46. }
  47. }
  48. return hash, nil
  49. }
  50. // Encrypt 加密文本
  51. func (cs *CryptoService) Encrypt(plaintext string) (string, error) {
  52. // 如果已经是加密文本,直接返回
  53. if cs.IsEncrypted(plaintext) {
  54. return plaintext, nil
  55. }
  56. block, err := aes.NewCipher(cs.key)
  57. if err != nil {
  58. return "", fmt.Errorf("创建密码块失败: %w", err)
  59. }
  60. gcm, err := cipher.NewGCM(block)
  61. if err != nil {
  62. return "", fmt.Errorf("创建GCM模式失败: %w", err)
  63. }
  64. nonce := make([]byte, gcm.NonceSize())
  65. if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
  66. return "", fmt.Errorf("生成随机数失败: %w", err)
  67. }
  68. ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
  69. encoded := base64.StdEncoding.EncodeToString(ciphertext)
  70. // 添加前缀标识
  71. return cs.prefix + encoded, nil
  72. }
  73. // Decrypt 解密文本
  74. func (cs *CryptoService) Decrypt(input string) (string, error) {
  75. // 如果不是加密文本,直接返回原文本
  76. if !cs.IsEncrypted(input) {
  77. return input, nil
  78. }
  79. // 移除前缀
  80. encoded := strings.TrimPrefix(input, cs.prefix)
  81. ciphertext, err := base64.StdEncoding.DecodeString(encoded)
  82. if err != nil {
  83. // 如果不是有效的Base64,返回原文本
  84. return input, nil
  85. }
  86. block, err := aes.NewCipher(cs.key)
  87. if err != nil {
  88. return "", fmt.Errorf("创建密码块失败: %w", err)
  89. }
  90. gcm, err := cipher.NewGCM(block)
  91. if err != nil {
  92. return "", fmt.Errorf("创建GCM模式失败: %w", err)
  93. }
  94. if len(ciphertext) < gcm.NonceSize() {
  95. return "", errors.New("密文太短")
  96. }
  97. nonce, ciphertext := ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():]
  98. plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
  99. if err != nil {
  100. // 如果解密失败,返回原文本(可能是格式相似但不是真正的加密文本)
  101. return input, nil
  102. }
  103. return string(plaintext), nil
  104. }
  105. // IsEncrypted 检查文本是否已加密
  106. func (cs *CryptoService) IsEncrypted(text string) bool {
  107. return strings.HasPrefix(text, cs.prefix)
  108. }
  109. // EncryptOrDecrypt 智能加密或解密
  110. // 如果输入是明文则加密,如果已是密文则解密
  111. func (cs *CryptoService) EncryptOrDecrypt(input string) (string, error) {
  112. if cs.IsEncrypted(input) {
  113. return cs.Decrypt(input)
  114. }
  115. return cs.Encrypt(input)
  116. }
  117. // EncryptIfNeeded 如果需要则加密
  118. func (cs *CryptoService) EncryptIfNeeded(input string) (string, error) {
  119. if cs.IsEncrypted(input) {
  120. return input, nil
  121. }
  122. return cs.Encrypt(input)
  123. }
  124. // DecryptIfNeeded 如果需要则解密
  125. func (cs *CryptoService) DecryptIfNeeded(input string) (string, error) {
  126. if cs.IsEncrypted(input) {
  127. return cs.Decrypt(input)
  128. }
  129. return input, nil
  130. }