项目地址

这个项目是很久以前的,当时go能力有限,写的不尽人意。刚好最近有加密文件的需求,所以就完善了相关逻辑。

之前的方案还依赖 Seek(offset int64, whence int) (int64, error) ,看了go很多源码,都说Seek不可靠。所以目前改为纯ReaderWriter这两种接口,当然文件的结构也必须改变。

因为自带hash校验,因此内容连一个字节都不能被篡改,安全性很高。而且随机的aes密码也是通过rsa进行加密,因此只要妥善保管好rsa的私钥就能保证万无一失。

加密后内容结构如下所示:

rsa密文长度 rsa加密aes密码后的密文 aes加密内容 数据hash值
len(rsa(password)) rsa(password) aesEnc(data) hash(data)

下面是示例代码:

package main
import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"flag"
	"io"
	"log"
	"os"
	"github.com/jan-bar/EncryptionFile"
)
func main() {
	org := flag.String("f", "", "enc file path")
	flag.Parse()
	src := *org // dst为生成的加密文件,cmp是通过解密dst生成的文件
	dst, cmp := src+".dst", src+".cmp"
	var pri, pub bytes.Buffer // 生成一对公私钥数据
	err := EncryptionFile.GenRsaKey(2048, &pub, &pri)
	if err != nil {
		log.Fatal(err)
	}
	//goland:noinspection GoUnhandledErrorResult
	enc := func() error {
		fr, err := os.Open(src)
		if err != nil {
			return err
		}
		defer fr.Close()
		fw, err := os.Create(dst)
		if err != nil {
			return err
		}
		defer fw.Close()
		return EncryptionFile.EncData(fr, fw, pub.Bytes(), md5.New())
	}
	if err = enc(); err != nil {
		log.Fatal(err)
	}
	//goland:noinspection GoUnhandledErrorResult
	dec := func() error {
		fr, err := os.Open(dst)
		if err != nil {
			return err
		}
		defer fr.Close()
		fw, err := os.Create(cmp)
		if err != nil {
			return err
		}
		defer fw.Close()
		return EncryptionFile.DecData(fr, fw, pri.Bytes(), md5.New())
	}
	if err = dec(); err != nil {
		log.Fatal(err)
	}
	md5Src, err := md5file(src)
	if err != nil {
		log.Fatal(err)
	}
	md5Org, err := md5file(cmp)
	if err != nil {
		log.Fatal(err)
	}
	if md5Src != md5Org {
		log.Fatalf("src(%s) != org(%s)", md5Src, md5Org)
	}
}
func md5file(s string) (string, error) {
	fr, err := os.Open(s)
	if err != nil {
		return "", err
	}
	//goland:noinspection GoUnhandledErrorResult
	defer fr.Close()
	h := md5.New()
	_, err = io.Copy(h, fr)
	if err != nil {
		return "", err
	}
	return hex.EncodeToString(h.Sum(nil)), nil
}