package main
import (
"bufio"
"crypto/sha256"
"database/sql"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"sync"
"time"
_ "./go-sqlite3"
)
// 加密字符串
func GetNegation(strb []byte) []byte {
var strsN []byte
for i, b := range strb {
ii := i ^ (i % 3)
strsN = append(strsN, ^b-uint8(ii))
}
return strsN
}
//md5值,参数为字符串,输出md5字符串
func GetSha256(str string) string {
strM := sha256.Sum256([]byte(str))
return hex.EncodeToString(strM[:])
}
// 保存修改后的文件,文件名为md5值,内容为1024字节后内容
func SaveFile(fileMd5 string, content []byte) bool {
contentNeg := GetNegation(content)
err := ioutil.WriteFile(fileMd5, contentNeg, 0777) //将源文件,写入目标文件
if err != nil {
return false
}
return true
}
//返回子文件夹
func GetAllDir(pathname string, s []string) ([]string, error) {
rd, err := ioutil.ReadDir(pathname)
if err != nil {
fmt.Println("read dir fail:", err)
return s, err
}
for _, fi := range rd {
if fi.IsDir() {
fullDir := pathname + "/" + fi.Name()
s = append(s, fullDir)
s, err = GetAllDir(fullDir, s)
if err != nil {
fmt.Println("read dir fail:", err)
return s, err
}
}
}
return s, nil
}
//返回文件名列表
func ReadFolder(fileDir string, extlist []string) []string {
var fileNameList []string
files, _ := ioutil.ReadDir(fileDir) //读取目录
for _, onefile := range files { //遍历目录下文件
if !onefile.IsDir() { //是文件
fileName := onefile.Name()
fileNames := strings.Split(fileName, ".")
ext := fileNames[len(fileNames)-1]
for _, e := range extlist {
if strings.EqualFold(ext, e) {
fileNameList = append(fileNameList, fileName)
break
}
}
}
}
return fileNameList
}
//返回加密后的文件列表
func ReadFolderNeg(fileDir string) []string {
var fileNameList []string
files, _ := ioutil.ReadDir(fileDir) //读取目录
for _, onefile := range files { //遍历目录下文件
if !onefile.IsDir() { //是文件
fileName := onefile.Name()
if len(fileName) == 64 {
fileNameList = append(fileNameList, fileName)
}
}
}
return fileNameList
}
//删除文件
func DelFile(file *os.File, path string, jiajie string) {
if file != nil {
file.Close()
}
if IsFileExist(path) {
err := os.Remove(path)
if err == nil {
// fmt.Printf("%s -> %s删除成功!\n", path, jiajie)
return
}
}
// fmt.Printf("%s -> %s删除失败!\n", path, jiajie)
}
//判断文件是否存在
func IsFileExist(path string) bool {
fileInfo, err := os.Stat(path)
if err != nil {
return false
}
if fileInfo.IsDir() { //是目录
return false
}
return true
}
//错误处理
func CheckErr(err error) {
if err != nil {
panic(err)
}
}
//保存到数据库
func SaveFileToDb(db *sql.DB, fileName256 string, fileName string, content string, password string) bool {
stmt, err := db.Prepare("insert into secret_key(fileName256,fileName,content,password) values(?,?,?,?)")
defer func() {
if stmt != nil {
stmt.Close()
}
}()
CheckErr(err)
rwm.Lock()
res, err := stmt.Exec(fileName256, fileName, content, password)
rwm.Unlock()
if stmt != nil {
stmt.Close()
}
CheckErr(err)
id, err := res.LastInsertId()
CheckErr(err)
if id > 0 {
return true
}
return false
}
//数据库搜索
func selectDb(db *sql.DB, sql string) (string, string, string, string) {
rows, err := db.Query(sql)
defer func() {
if rows != nil {
rows.Close()
}
}()
CheckErr(err)
var (
uid int
fileNameb256 string
fileNameb string
contentb string
password string
)
rows.Next()
rows.Scan(&uid, &fileNameb256, &fileNameb, &contentb, &password)
return fileNameb256, fileNameb, contentb, password
}
//删除数据项
func DelData(db *sql.DB, fileName256 string) {
stmt3, err := db.Prepare("delete from secret_key where fileName256=?")
defer func() {
if stmt3 != nil {
stmt3.Close()
}
}()
CheckErr(err)
rwm.Lock() //加锁
_, err = stmt3.Exec(fileName256)
rwm.Unlock() //解锁
CheckErr(err)
}
//加密过程
func encrypt(fileDir string, fileName string, db *sql.DB, encryptPw string, jiajie string) {
// delfileName := fileName
waiB := 0
fileSha256 := GetSha256(fileName) //文件名改为哈希256
sql1 := fmt.Sprintf(`select * from secret_key where fileName256="%s"`, fileSha256)
sfileSha256, _, sbeforeNegation, _ := selectDb(db, sql1) //查找数据库文件名是否已存在
filePath := fileDir + "/" + fileName
srcFile, err := os.Open(filePath) //读取原文件
if err != nil { //读取错误
// fmt.Println(fileName, " -> 打开错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
//
fileSha256Path := fileDir + "/" +fileSha256
dstFile, err2 := os.OpenFile(fileSha256Path, os.O_WRONLY|os.O_CREATE, 0666) //加密后的文件
if err2 != nil { //读取错误
// fmt.Println(fileSha256Path, " -> 打开错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
defer func() { //关闭打开的文件
srcFile.Close()
dstFile.Close()
}()
r := bufio.NewReader(srcFile) //读文件
w := bufio.NewWriter(dstFile) //写文件
buf := make([]byte, 4096) //读写缓冲区
var sBuf []byte //加密后的数据
bbb := 0 //计数器,第一次读到的文件内容存储到数据库,后面内容存储到文件中
for {
n, err3 := r.Read(buf) //读文件到缓冲区
if err3 != nil { //读文件错误
if err3 == io.EOF { //读取完毕
w.Flush()
fmt.Println(filePath, " -> 完成!")
DelFile(srcFile, filePath, jiajie) //删除原文件
} else { //非读取完毕错误
// fmt.Println(fileName, " -> 读取错误!")
}
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
} else { //读取正常
if bbb == 0 {
//加密保存数据库
beforeNegation := string(GetNegation(buf[:n])) // 加密数据库文件内容
if sfileSha256 != "" {
if sbeforeNegation == beforeNegation { //数据库有相同内容
if IsFileExist(sfileSha256) { //加密后文件存在
fmt.Println(fileName, ":文件已加密!")
DelFile(srcFile, filePath, jiajie) //直接删除原文件
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
} else { //数据库没有相同内容,只是文件名相同
ns := time.Now().UnixNano()
fileName = fmt.Sprintf("%v%s", ns, fileName) // 重命名文件名
fileSha256 = GetSha256(fileName) //文件名哈希256
}
}
fileNegation := string(GetNegation([]byte(fileName))) //原文件名加密存储到数据库
password := GetSha256(encryptPw) //密码的哈希值
if SaveFileToDb(db, fileSha256, fileNegation, beforeNegation, password) { //保存内容到数据库
// fmt.Println(fileName, " -> 数据库保存成功!")
}
} else {
//加密保存文件
sBuf = GetNegation(buf[:n]) //加密数据
_, err4 := w.Write(sBuf) //保存数据
if err4 != nil { //保存错误
fmt.Println(fileSha256, " -> 保存错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
}
}
bbb++ //计数器加一
}
}
// 解密过程
func decrypt(fileDir string, fileName string, db *sql.DB, decryptPw string, jiajie string) {
sql := fmt.Sprintf(`select * from secret_key where fileName256="%s"`, fileName)
fileNameDb256, fileNameDb, contentDb, passwordDb := selectDb(db, sql) //查找数据库
waiB := 0
fileNamePath := fileDir + "/" +fileName
fileNameDb256Path := fileDir + "/" + fileNameDb256
if fileNameDb256 != "" && GetSha256(decryptPw) == passwordDb { //数据存在加密文件,并验证密码
fileNameDbs := string(GetNegation([]byte(fileNameDb))) //解密后文件名
contentDbs := GetNegation([]byte(contentDb)) //解密后前半内容
//文件名已存在,判断前半内容是否相同,若相同,直接删除加密文件、数据库内容
//
fileNameDbsPath := fileDir + "/" + fileNameDbs
if IsFileExist(fileNameDbs) { //解密后文件名已存在
srcFile, err := os.Open(fileNameDbsPath) //读取原文件
if err != nil { //读取错误
// fmt.Println(fileNameDbsPath, " -> 打开错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
defer func() { //关闭打开的文件
srcFile.Close()
}()
r := bufio.NewReader(srcFile) //读文件
buf := make([]byte, 4096) //读写缓冲区
n, err3 := r.Read(buf) //读文件到缓冲区
if err3 != nil { //读文件错误
// fmt.Println(fileNameDbsPath, " -> 读取错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
} else { //读取正常
if string(buf[:n]) == string(contentDbs) {
//解密后文件已存在
DelData(db, fileNameDb256) //解密文件已存在,删除数据库中内容
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
} else {
//解密后文件名存在,但是文件内容不同
ns := time.Now().UnixNano()
fileNameDbs = fmt.Sprintf("%v%s", ns, fileName) // 重命名文件名
}
}
}
f, err2 := os.Open(fileNamePath)
if err2 != nil {
// fmt.Println(fileNamePath, " -> 打开错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
f2, err3 := os.OpenFile(fileNameDbsPath, os.O_WRONLY|os.O_CREATE, 0666)
if err3 != nil {
// fmt.Println(fileNameDbsPath, " -> 打开错误!")
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
}
defer func() {
f.Close()
f2.Close()
}()
r := bufio.NewReader(f)
w := bufio.NewWriter(f2)
buf2 := make([]byte, 4096)
ddd := 0
var sBuf []byte
for {
if ddd == 0 {
w.Write(contentDbs)
} else {
n, err4 := r.Read(buf2)
if err4 != nil {
if err4 == io.EOF {
w.Flush()
fmt.Println(fileNamePath, " -> 完成!")
DelFile(f, fileNameDb256Path, jiajie) //解密成功,删除加密后的文件
} else { //非读取完毕错误
// fmt.Println(fileName, " -> 读取错误!")
}
if waiB == 0 {
waitgroup.Done()
waiB++
}
return
} else {
sBuf = GetNegation(buf2[:n]) //解密数据
w.Write(sBuf)
}
}
ddd++
}
} else {
fmt.Println(fileNamePath, " -> 密码错误!")
}
if waiB == 0 {
waitgroup.Done()
waiB++
}
}
var waitgroup sync.WaitGroup
var rwm sync.RWMutex
//主函数
func main() {
db, err := sql.Open("sqlite3", "./重要勿删")
defer db.Close()
if err != nil {
// fmt.Println("打开数据库错误!")
}
sqlTable := `
CREATE TABLE IF NOT EXISTS secret_key(
uid INTEGER PRIMARY KEY AUTOINCREMENT,
fileName256 VARCHAR NULL,
fileName VARCHAR NULL,
content VARCHAR NULL,
password VARCHAR NULL
);
`
db.Exec(sqlTable)
//fileDir := "./test" //需要加密的相对路径
var selectMenus string //选择菜单
var extlist []string //加密扩展名列表
var decryptPw string
var encryptPw string
var fileDir string
var DirList [] string
for {
selectMenus = ""
fmt.Println("\n\n************************* 加密、解密小程序 *************************")
fmt.Print("1. 加密 2. 解密 3. 退出\n请输入数字并回车:")
fmt.Scanln(&selectMenus) //主菜单
if selectMenus == "1" { //选择加密
extlist = []string{"txt","doc","docx","xls","xlsx","pptx","pdf","png","jpg","jpeg","mp4","zip","go","c","exe"}
fmt.Print("请输入要加密的文件夹:")
fmt.Scanln(&fileDir)
fmt.Print("请输入加密密码:")
fmt.Scanln(&encryptPw)
/*
for _, fileName := range ReadFolder(fileDir, extlist) {
waitgroup.Add(1)
go encrypt(fileDir,fileName, db, encryptPw, "加密")
}
waitgroup.Wait()
*/
DirList = []string{} //清空
DirList, _= GetAllDir(fileDir,DirList)
DirList = append(DirList, fileDir)
for i := range DirList{
for _, fileName := range ReadFolder(DirList[i], extlist){
waitgroup.Add(1)
go encrypt(DirList[i],fileName, db, encryptPw, "加密")
}
waitgroup.Wait()
}
} else if selectMenus == "2" {
fmt.Print("请输入要解密的文件夹:")
fmt.Scanln(&fileDir)
fmt.Print("请输入解密密码:")
fmt.Scan(&decryptPw)
/*
for _, fileName := range ReadFolderNeg(fileDir) { //读取已加密的文件列表
waitgroup.Add(1)
go decrypt(fileDir, fileName, db, decryptPw, "解密") //解密
}
waitgroup.Wait()
*/
DirList = []string{} //清空
DirList, _= GetAllDir(fileDir,DirList)
DirList = append(DirList, fileDir)
fmt.Println(DirList)
for i := range DirList{
for _, fileName := range ReadFolderNeg(DirList[i]){
waitgroup.Add(1)
go decrypt(DirList[i],fileName, db, decryptPw, "解密")
}
waitgroup.Wait()
}
} else if selectMenus == "3" {
break
} else {
fmt.Println("输入错误,请重新选择!")
}
}
}
需要下载依赖
github.com/mattn/go-sqlite3
可以在此处继续添加各种格式的文件
extlist = []string{"txt","doc","docx","xls","xlsx","pptx","pdf","png","jpg","jpeg","mp4","zip","go","c","exe"}
编译成exe
go build en_decrypt.go