文件压缩、加密与解压缩&解密
1、注意事项
1、先压缩、在加密(加密后变成2进制在压缩没啥效果);先解密、在解压缩
· 加密后的数据由于其高度的随机性和熵值,压缩效果会非常有限
2、需要压缩到新文件,需要清理原文件;还原文件后 也需要删除原加密文件
· 避免原文件积累占用磁盘
2、代码
cat encry_gzip_tarfiles.go
package main
import (
"archive/tar"
"bytes"
"compress/gzip"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
//生成用于 AES 加密的密钥通常涉及生成一个足够强度的随机字节序列
func generateAESKey(size int) ([]byte, error) {
key := make([]byte, size)
if _, err := rand.Read(key); err != nil {
return nil, fmt.Errorf("failed to generate key: %v", err)
}
return key, nil
}
func compressAndEncrypt(filename string, key []byte) error {
// 读取原始文件
plaintext, err := os.ReadFile(filename)
if err != nil {
return err
}
// 先进行压缩
var b bytes.Buffer
gz := gzip.NewWriter(&b)
if _, err := gz.Write(plaintext); err != nil {
return err
}
if err := gz.Close(); err != nil {
return err
}
compressedData := b.Bytes()
// 设置加密
block, err := aes.NewCipher(key)
if err != nil {
return err
}
ciphertext := make([]byte, aes.BlockSize+len(compressedData))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return err
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], compressedData)
// 写入加密后的压缩文件
encryptedFile, err := os.Create(filename + ".gz.enc")
if err != nil {
return err
}
defer encryptedFile.Close()
if _, err = encryptedFile.Write(ciphertext); err != nil {
return err
}
// 删除原始文件
err = os.Remove(filename)
if err != nil {
return err
}
return nil
}
func TarFiles(sourceDir, tarFilename string) error {
// 创建 tar 文件
tarFile, err := os.Create(tarFilename)
if err != nil {
return err
}
defer tarFile.Close()
// 创建 tar.Writer 对象
tarWriter := tar.NewWriter(tarFile)
defer tarWriter.Close()
// 遍历目录
err = filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 创建 tar 头部信息
header, err := tar.FileInfoHeader(info, "")
if err != nil {
return err
}
// 设置头部信息的 Name 属性为文件相对于 sourceDir 的路径
header.Name, err = filepath.Rel(sourceDir, path)
if err != nil {
return err
}
// 写入头部信息
if err := tarWriter.WriteHeader(header); err != nil {
return err
}
// 如果是普通文件,则写入文件内容
if !info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
if _, err := io.Copy(tarWriter, file); err != nil {
return err
}
}
return nil
})
return err
}
// func uploadToS3(bucket, item, filename string) error {
// sess := session.Must(session.NewSession())
// svc := s3.New(sess)
// file, err := os.Open(filename)
// if err != nil {
// return err
// }
// defer file.Close()
// _, err = svc.PutObject(&s3.PutObjectInput{
// Bucket: aws.String(bucket),
// Key: aws.String(item),
// Body: file,
// })
// return err
// }
// decryptAndDecompress 解密并解压缩文件
func decryptAndDecompress(filename string, key []byte) error {
// 读取加密的文件
ciphertext, err := os.ReadFile(filename)
if err != nil {
return err
}
// 设置解密
block, err := aes.NewCipher(key)
if err != nil {
return err
}
if len(ciphertext) < aes.BlockSize {
return io.ErrUnexpectedEOF
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
// 解压缩数据
b := bytes.NewBuffer(ciphertext)
gz, err := gzip.NewReader(b)
if err != nil {
return err
}
defer gz.Close()
// 读取解压缩后的数据
decompressedData, err := io.ReadAll(gz)
if err != nil {
return err
}
// 写入解压缩后的文件
newFilename := strings.TrimSuffix(filename, ".gz.enc")
decompressedFile, err := os.Create(newFilename)
// decompressedFile, err := os.Create(filename + ".dec")
if err != nil {
return err
}
defer decompressedFile.Close()
if _, err = decompressedFile.Write(decompressedData); err != nil {
return err
}
err = os.Remove(filename)
if err != nil {
return err
}
return nil
}
func encryptAndCompressFiles(files []string, key []byte) error {
for _, filename := range files {
err := compressAndEncrypt(filename, key)
if err != nil {
return err
}
}
return nil
}
func decryptAndDecompressFiles(files []string, key []byte) error {
for _, filename := range files {
err := decryptAndDecompress(filename, key)
if err != nil {
return err
}
}
return nil
}
func getAllFiles(dir string) ([]string, error) {
var files []string
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 跳过目录
if info.IsDir() {
return nil
}
files = append(files, path)
return nil
})
if err != nil {
return nil, err
}
return files, nil
}
func UntarFiles(tarFilename, destDir string) error {
// 打开 tar 文件
tarFile, err := os.Open(tarFilename)
if err != nil {
return err
}
defer tarFile.Close()
// 创建 tar.Reader 对象
tarReader := tar.NewReader(tarFile)
// 遍历 tar 中的所有项目
for {
header, err := tarReader.Next()
if err == io.EOF {
break // 文件结束
}
if err != nil {
return err
}
// 目标文件路径
targetPath := filepath.Join(destDir, header.Name)
switch header.Typeflag {
case tar.TypeDir: // 是目录
// 创建目录
if err := os.MkdirAll(targetPath, 0755); err != nil {
return err
}
case tar.TypeReg: // 是普通文件
// 创建文件
outFile, err := os.Create(targetPath)
if err != nil {
return err
}
defer outFile.Close()
// 复制文件内容
if _, err := io.Copy(outFile, tarReader); err != nil {
return err
}
}
}
return nil
}
func main() {
// //生成随机加密key
// prikey, err := generateAESKey(32) // 生成一个256位的AES密钥,加、解密用到
// //压缩、加密子文件、打包为一个备份文件
// sourceDir := "1046/2024_03_01/mymongo/"
// inifiles, err := getAllFiles(sourceDir)
// if err != nil {
// fmt.Println("获取文件列表失败:", err)
// return
// }
// if err != nil {
// fmt.Println("Error generating prikey:", err)
// return
// }
// fmt.Printf("Generated prikey: %xn", prikey)
// fmt.Println("开始加密、压缩文件...")
// err = encryptAndCompressFiles(inifiles, prikey)
// if err != nil {
// fmt.Println("加密、压缩文件失败:", err)
// return
// }
// fmt.Println("开始打包加密子文件...")
// tarFilename := "sre-core.tar"
// if err := TarFiles(sourceDir, tarFilename); err != nil {
// panic(err)
// }
// 解包备份文件、解密、解压缩
tarFilename := "sre-core.tar"
destDir := "extracted_files/"
if err := UntarFiles(tarFilename, destDir); err != nil {
panic(err)
}
// sourceDir := "1046/2024_03_01/mymongo/"
encr_bakfiles, err := getAllFiles(destDir)
if err != nil {
fmt.Println("获取文件列表失败:", err)
return
}
fmt.Println("开始解密、解压缩文件...")
pprikey := "761d400147d02ccad0e9fb0929560311867019c5ba46491f5bd04a7532659600"
prikeyBytes, err := hex.DecodeString(pprikey) // 解码十六进制字符串
if err != nil {
panic(err) // 处理可能的解码错误
}
err = decryptAndDecompressFiles(encr_bakfiles, prikeyBytes)
if err != nil {
panic(err)
} else {
fmt.Println("备份文件解密、解压缩完成!!!")
}
}