├── .gitignore ├── README.md ├── build.sh ├── compression └── gzip.go ├── crypto └── aes.go ├── go.mod ├── go.sum ├── main.go └── util └── util.go /.gitignore: -------------------------------------------------------------------------------- 1 | secret 2 | source 3 | private.pem 4 | *.swp 5 | build 6 | .idea 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 用于文件加解密 2 | * 基于Go使用AES 128进行文件加解密 3 | * 提供gzip进行文件压缩,更快的网络传输速度 4 | 5 | ### 初衷 6 | * 很多资料需要保存在网盘中,但无奈与现在的网络安全实在是放不下心。所以开发这个小工具对目标目录的文件进行加密,加密后可以安心的保存至网盘中了,需要查看时再使用本工具进行解密即可。 7 | * 文件太多的时候上行带宽实在是过慢,对文件进行压缩能优化一些时间成本 8 | 9 | ### 使用方法 10 | 使用加密功能后会在指定目录生成secret文件夹,目录结构与源目录结构相同 11 | 解密功能会在指定路径输出该源文件 12 | ```shell 13 | ### 加密 14 | ./encryption -s "/home/photos" -t encode 15 | 16 | ### 解密 17 | ./encryption -s "./secret" -t decode 18 | ``` 19 | 20 | ### Tips 21 | * 请务必管理好工具生成的私钥文件,否则极大可能造成文件无法解密的结果 22 | * 工具仍处在Bate阶段,不建议对机密性或重要性文件进行加解密 23 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | GOOS=linux GOARCH=amd64 go build -o build/linux_amd64/encryption -ldflags '-s -w' main.go 6 | GOOS=windows GOARCH=amd64 go build -o build/windows_amd64/encryption.exe -ldflags '-s -w' main.go 7 | GOOS=darwin GOARCH=amd64 go build -o build/darwin_amd64/encryption -ldflags '-s -w' main.go 8 | 9 | cd build 10 | 11 | tar zcvf linux_amd64.tar.gz linux_amd64 12 | tar zcvf windows_amd64.tar.gz windows_amd64 13 | tar zcvf darwin_amd64.tar.gz darwin_amd64 14 | -------------------------------------------------------------------------------- /compression/gzip.go: -------------------------------------------------------------------------------- 1 | package compression 2 | 3 | import ( 4 | "bytes" 5 | "compress/zlib" 6 | "io/ioutil" 7 | "log" 8 | ) 9 | 10 | func Comporession(data []byte) (*[]byte, error) { 11 | var buf bytes.Buffer 12 | w := zlib.NewWriter(&buf) 13 | if _, err := w.Write(data); err != nil { 14 | return nil, err 15 | } 16 | if err := w.Close(); err != nil { 17 | return nil, err 18 | } 19 | cData := buf.Bytes() 20 | 21 | return &cData, nil 22 | } 23 | 24 | func UnComporession(data []byte) (*[]byte, error) { 25 | b := bytes.NewReader(data) 26 | r, err := zlib.NewReader(b) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | uData, err := ioutil.ReadAll(r) 32 | if err != nil { 33 | log.Fatal(data) 34 | return nil, err 35 | } 36 | r.Close() 37 | 38 | return &uData, nil 39 | } 40 | -------------------------------------------------------------------------------- /crypto/aes.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "Desktop/compression" 5 | "bytes" 6 | "crypto/aes" 7 | "crypto/cipher" 8 | "io/ioutil" 9 | "log" 10 | "math/rand" 11 | "os" 12 | filepath2 "path/filepath" 13 | "time" 14 | ) 15 | 16 | func EncryptFile(filepath string, savepath string, keyFileName string) error { 17 | loadKey, err := ioutil.ReadFile(keyFileName) 18 | if err != nil { 19 | return err 20 | } 21 | fileData, err := ioutil.ReadFile(filepath) 22 | if err != nil { 23 | return err 24 | } 25 | data, err := AesEncrypt(fileData, loadKey) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | 30 | 31 | // 进行压缩 32 | cData, err := compression.Comporession(data) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | absPath := filepath2.Dir(savepath) 38 | if err := os.MkdirAll(absPath, 0755); err != nil { 39 | 40 | } 41 | 42 | if err := ioutil.WriteFile(savepath, *cData, 0644); err != nil { 43 | return err 44 | } 45 | return nil 46 | } 47 | 48 | func DecryptFile(filepath string, savepath string, keyFileName string) error { 49 | loadKey, err := ioutil.ReadFile(keyFileName) 50 | if err != nil { 51 | return err 52 | } 53 | fileData, err := ioutil.ReadFile(filepath) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | // 进行解压 59 | uData, err := compression.UnComporession(fileData) 60 | if err != nil { 61 | log.Fatal(uData) 62 | return err 63 | } 64 | 65 | data, err := AesDecrypt(*uData, loadKey) 66 | if err != nil { 67 | log.Fatal("Error: 私钥不正确.", err) 68 | } 69 | 70 | absPath := filepath2.Dir(savepath) 71 | if err := os.MkdirAll(absPath, 0755); err != nil { 72 | } 73 | 74 | if err := ioutil.WriteFile(savepath, []byte(data), 0644); err != nil { 75 | return err 76 | } 77 | 78 | return nil 79 | } 80 | 81 | func GenAesKey(bits int, keyFileName string) error { 82 | str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 83 | bytes := []byte(str) 84 | result := []byte{} 85 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 86 | for i := 0; i < bits; i++ { 87 | result = append(result, bytes[r.Intn(len(bytes))]) 88 | } 89 | 90 | if err := ioutil.WriteFile(keyFileName, result, 0644); err != nil { 91 | return err 92 | } 93 | 94 | return nil 95 | } 96 | 97 | func PKCS5Padding(ciphertext []byte, blockSize int) []byte { 98 | padding := blockSize - len(ciphertext)%blockSize 99 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 100 | return append(ciphertext, padtext...) 101 | } 102 | 103 | func PKCS5UnPadding(origData []byte) []byte { 104 | length := len(origData) 105 | unpadding := int(origData[length-1]) 106 | return origData[:(length - unpadding)] 107 | } 108 | 109 | func AesEncrypt(origData, key []byte) ([]byte, error) { 110 | block, err := aes.NewCipher(key) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | blockSize := block.BlockSize() 116 | origData = PKCS5Padding(origData, blockSize) 117 | blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) 118 | crypted := make([]byte, len(origData)) 119 | blockMode.CryptBlocks(crypted, origData) 120 | return crypted, nil 121 | } 122 | 123 | func AesDecrypt(crypted, key []byte) ([]byte, error) { 124 | block, err := aes.NewCipher(key) 125 | if err != nil { 126 | return nil, err 127 | } 128 | 129 | blockSize := block.BlockSize() 130 | blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) 131 | origData := make([]byte, len(crypted)) 132 | blockMode.CryptBlocks(origData, crypted) 133 | origData = PKCS5UnPadding(origData) 134 | return origData, nil 135 | } 136 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module Desktop 2 | 3 | require ( 4 | fyne.io/fyne v1.0.0 // indirect 5 | github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 // indirect 6 | github.com/go-gl/glfw v0.0.0-20190217072633-93b30450e032 // indirect 7 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect 8 | github.com/srwiley/oksvg v0.0.0-20190105194046-ccbc7673cdf3 // indirect 9 | github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e // indirect 10 | golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f // indirect 11 | golang.org/x/net v0.0.0-20190328230028-74de082e2cca // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | fyne.io/fyne v1.0.0 h1:YkBV7ruvWISf37Bi46PaoXoF1YP8T1s2UJITdp8DC74= 2 | fyne.io/fyne v1.0.0/go.mod h1:7zZ/iK2TrnF2/9eDvB7EEbTtKdbHzQfREhUyFmvAKeM= 3 | github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= 4 | github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= 5 | github.com/go-gl/glfw v0.0.0-20190217072633-93b30450e032 h1:WUDJN6o1AZlnNR0UZ11zsr0Quh44CV7svcg6VzEsySc= 6 | github.com/go-gl/glfw v0.0.0-20190217072633-93b30450e032/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 7 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= 8 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= 9 | github.com/srwiley/oksvg v0.0.0-20190105194046-ccbc7673cdf3 h1:8REQ/vZZIZFaZedUSHd7TVkK0CF4heqGtmyz30gCxm8= 10 | github.com/srwiley/oksvg v0.0.0-20190105194046-ccbc7673cdf3/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= 11 | github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e h1:FFotfUvew9Eg02LYRl8YybAnm0HCwjjfY5JlOI1oB00= 12 | github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= 13 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 14 | golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f h1:FO4MZ3N56GnxbqxGKqh+YTzUWQ2sDwtFQEZgLOxh9Jc= 15 | golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 16 | golang.org/x/net v0.0.0-20190328230028-74de082e2cca h1:hyA6yiAgbUwuWqtscNvWAI7U1CtlaD1KilQ6iudt1aI= 17 | golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 18 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 19 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 20 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 21 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "Desktop/crypto" 5 | "Desktop/util" 6 | "flag" 7 | "io/ioutil" 8 | "log" 9 | "strings" 10 | ) 11 | 12 | const keyFileName = "private.pem" 13 | 14 | var fileDir string 15 | var t = flag.String("t", "encode", "encode 文件加密\ndecode文件解密") 16 | var s = flag.String("s", "", "源文件夹") 17 | var d = flag.String("d", "./", "输出文件夹") 18 | 19 | func main() { 20 | log.SetFlags(log.Lshortfile | log.LstdFlags) 21 | 22 | ParseArgs() 23 | var isExists bool 24 | var err error 25 | if isExists, err = util.CheckPrivateKeyExists(keyFileName); err != nil { 26 | log.Fatal("无法读取或私钥文件: ", err) 27 | } 28 | if isExists == false { 29 | err := crypto.GenAesKey(32, keyFileName) 30 | if err != nil { 31 | log.Fatal("无法创建私钥文件: ", err) 32 | } 33 | } 34 | 35 | fileDir = *s 36 | if GetLastCharset(fileDir) != "/" { 37 | fileDir += "/" 38 | } 39 | 40 | if *t == "encode" { 41 | EncodeDir(fileDir) 42 | } else { 43 | DecodeDir(fileDir) 44 | } 45 | } 46 | 47 | func ParseArgs() { 48 | flag.Parse() 49 | 50 | if *s == "" { 51 | log.Fatal("缺少输入文件夹 --help Usage ") 52 | } 53 | 54 | if *t != "encode" && *t != "decode" { 55 | log.Fatal("-t 参数类型错误 --help Usage ") 56 | } 57 | } 58 | 59 | func GetLastCharset(data string) string { 60 | str := []rune(data) 61 | return string(str[len(str)-1:]) 62 | } 63 | 64 | func EncodeDir(dir string) { 65 | files, err := ioutil.ReadDir(dir) 66 | if err != nil { 67 | log.Fatal("无法读取目标目录: ", err) 68 | } 69 | 70 | for _, item := range files { 71 | if item.IsDir() { 72 | EncodeDir(dir + item.Name() + "/") 73 | continue 74 | } 75 | newFilePath := strings.Replace(dir, fileDir, "", 1) + item.Name() 76 | sourcePath := dir + item.Name() 77 | savePath := *d + "secret/" + newFilePath + ".secret" 78 | 79 | log.Println("Encodeing... ", sourcePath) 80 | if err := crypto.EncryptFile(sourcePath, savePath, keyFileName); err != nil { 81 | log.Print(err) 82 | } 83 | } 84 | } 85 | 86 | func DecodeDir(dir string) { 87 | files, err := ioutil.ReadDir(dir) 88 | if err != nil { 89 | log.Fatal("无法读取目标目录: ", err) 90 | } 91 | 92 | for _, item := range files { 93 | if item.IsDir() { 94 | DecodeDir(dir + item.Name() + "/") 95 | continue 96 | } 97 | newFilePath := strings.Replace(dir, fileDir, "", 1) + item.Name() 98 | sourcePath := dir + item.Name() 99 | savePath := *d + "source/" + strings.Replace(newFilePath, ".secret", "", 1) 100 | 101 | log.Println("Decodeing... ", sourcePath) 102 | if err := crypto.DecryptFile(sourcePath, savePath, keyFileName); err != nil { 103 | log.Print(err) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | 8 | func CheckPrivateKeyExists(privateFileName string) (bool, error) { 9 | _, err := os.Stat(privateFileName) 10 | if err == nil { 11 | return true, err 12 | } 13 | 14 | if os.IsNotExist(err) { 15 | return false, nil 16 | } 17 | 18 | return false, err 19 | } 20 | --------------------------------------------------------------------------------