backup_crypto.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package backup
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "encoding/base64"
  7. "io"
  8. "os"
  9. "github.com/uozi-tech/cosy"
  10. )
  11. // AESEncrypt encrypts data using AES-256-CBC
  12. func AESEncrypt(data []byte, key []byte, iv []byte) ([]byte, error) {
  13. block, err := aes.NewCipher(key)
  14. if err != nil {
  15. return nil, cosy.WrapErrorWithParams(ErrEncryptData, err.Error())
  16. }
  17. // Pad data to be a multiple of block size
  18. padding := aes.BlockSize - (len(data) % aes.BlockSize)
  19. padtext := make([]byte, len(data)+padding)
  20. copy(padtext, data)
  21. // PKCS#7 padding
  22. for i := len(data); i < len(padtext); i++ {
  23. padtext[i] = byte(padding)
  24. }
  25. // Create CBC encrypter
  26. mode := cipher.NewCBCEncrypter(block, iv)
  27. encrypted := make([]byte, len(padtext))
  28. mode.CryptBlocks(encrypted, padtext)
  29. return encrypted, nil
  30. }
  31. // AESDecrypt decrypts data using AES-256-CBC
  32. func AESDecrypt(encrypted []byte, key []byte, iv []byte) ([]byte, error) {
  33. block, err := aes.NewCipher(key)
  34. if err != nil {
  35. return nil, cosy.WrapErrorWithParams(ErrDecryptData, err.Error())
  36. }
  37. // Create CBC decrypter
  38. mode := cipher.NewCBCDecrypter(block, iv)
  39. decrypted := make([]byte, len(encrypted))
  40. mode.CryptBlocks(decrypted, encrypted)
  41. // Remove padding
  42. padding := int(decrypted[len(decrypted)-1])
  43. if padding < 1 || padding > aes.BlockSize {
  44. return nil, ErrInvalidPadding
  45. }
  46. return decrypted[:len(decrypted)-padding], nil
  47. }
  48. // GenerateAESKey generates a random 32-byte AES key
  49. func GenerateAESKey() ([]byte, error) {
  50. key := make([]byte, 32) // 256-bit key
  51. if _, err := io.ReadFull(rand.Reader, key); err != nil {
  52. return nil, cosy.WrapErrorWithParams(ErrGenerateAESKey, err.Error())
  53. }
  54. return key, nil
  55. }
  56. // GenerateIV generates a random 16-byte initialization vector
  57. func GenerateIV() ([]byte, error) {
  58. iv := make([]byte, aes.BlockSize)
  59. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  60. return nil, cosy.WrapErrorWithParams(ErrGenerateIV, err.Error())
  61. }
  62. return iv, nil
  63. }
  64. // encryptFile encrypts a single file using AES encryption
  65. func encryptFile(filePath string, key []byte, iv []byte) error {
  66. // Read file content
  67. data, err := os.ReadFile(filePath)
  68. if err != nil {
  69. return cosy.WrapErrorWithParams(ErrReadFile, filePath)
  70. }
  71. // Encrypt file content
  72. encrypted, err := AESEncrypt(data, key, iv)
  73. if err != nil {
  74. return cosy.WrapErrorWithParams(ErrEncryptFile, filePath)
  75. }
  76. // Write encrypted content back
  77. if err := os.WriteFile(filePath, encrypted, 0644); err != nil {
  78. return cosy.WrapErrorWithParams(ErrWriteEncryptedFile, filePath)
  79. }
  80. return nil
  81. }
  82. // decryptFile decrypts a single file using AES decryption
  83. func decryptFile(filePath string, key []byte, iv []byte) error {
  84. // Read encrypted file content
  85. encryptedData, err := os.ReadFile(filePath)
  86. if err != nil {
  87. return cosy.WrapErrorWithParams(ErrReadEncryptedFile, err.Error())
  88. }
  89. // Decrypt file content
  90. decryptedData, err := AESDecrypt(encryptedData, key, iv)
  91. if err != nil {
  92. return cosy.WrapErrorWithParams(ErrDecryptFile, err.Error())
  93. }
  94. // Write decrypted content back
  95. if err := os.WriteFile(filePath, decryptedData, 0644); err != nil {
  96. return cosy.WrapErrorWithParams(ErrWriteDecryptedFile, err.Error())
  97. }
  98. return nil
  99. }
  100. // EncodeToBase64 encodes byte slice to base64 string
  101. func EncodeToBase64(data []byte) string {
  102. return base64.StdEncoding.EncodeToString(data)
  103. }
  104. // DecodeFromBase64 decodes base64 string to byte slice
  105. func DecodeFromBase64(encoded string) ([]byte, error) {
  106. return base64.StdEncoding.DecodeString(encoded)
  107. }