mirror of https://gitee.com/godoos/godoos.git
6 changed files with 684 additions and 260 deletions
@ -0,0 +1,297 @@ |
|||||
|
package files |
||||
|
|
||||
|
import ( |
||||
|
"encoding/base64" |
||||
|
"fmt" |
||||
|
"godo/libs" |
||||
|
"io" |
||||
|
"net/http" |
||||
|
"os" |
||||
|
"path/filepath" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
func HandleReadFile(w http.ResponseWriter, r *http.Request) { |
||||
|
path := r.URL.Query().Get("path") |
||||
|
if path == "" { |
||||
|
libs.ErrorMsg(w, "文件路径不能为空") |
||||
|
return |
||||
|
} |
||||
|
basePath, err := libs.GetOsDir() |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
fullFilePath := filepath.Join(basePath, path) |
||||
|
file, err := os.Open(fullFilePath) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
fileData, err := io.ReadAll(file) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
text := string(fileData) |
||||
|
//log.Printf("isPwd: %v", strData)
|
||||
|
if strings.HasPrefix(text, "link::") { |
||||
|
libs.SuccessMsg(w, text, "文件读取成功") |
||||
|
return |
||||
|
} |
||||
|
// 判断是否为加密文件
|
||||
|
isPwd := libs.IsEncryptedFile(text) |
||||
|
|
||||
|
if !isPwd { |
||||
|
// 未加密文件,直接返回
|
||||
|
text = base64.StdEncoding.EncodeToString(fileData) |
||||
|
// if len(text)%8 == 0 {
|
||||
|
// text += " "
|
||||
|
// }
|
||||
|
//log.Printf("fileData: %s", content)
|
||||
|
libs.SuccessMsg(w, text, "文件读取成功") |
||||
|
return |
||||
|
} |
||||
|
filePwd := r.Header.Get("pwd") |
||||
|
// 获取文件密钥
|
||||
|
fileSecret := libs.GetConfigString("filePwd") |
||||
|
if filePwd == "" && fileSecret == "" { |
||||
|
libs.Error(w, "加密文件,需要密码", "needPwd") |
||||
|
return |
||||
|
} |
||||
|
decodeFile := "" |
||||
|
needPwd := false |
||||
|
if fileSecret != "" { |
||||
|
decodeFile, err = libs.DecodeFile(fileSecret, text) |
||||
|
if err != nil { |
||||
|
libs.Error(w, "请输入文件密码", "needPwd") |
||||
|
return |
||||
|
} |
||||
|
needPwd = true |
||||
|
} |
||||
|
if filePwd != "" && !needPwd { |
||||
|
decodeFile, err = libs.DecodeFile(filePwd, text) |
||||
|
if err != nil { |
||||
|
libs.Error(w, "文件密码输入错误", "needPwd") |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
// if len(decodeFile)%8 == 0 {
|
||||
|
// decodeFile = decodeFile + " "
|
||||
|
// }
|
||||
|
libs.SuccessMsg(w, decodeFile, "加密文件读取成功") |
||||
|
} |
||||
|
func HandleWriteFile(w http.ResponseWriter, r *http.Request) { |
||||
|
path := r.URL.Query().Get("path") |
||||
|
if err := validateFilePath(path); err != nil { |
||||
|
libs.HTTPError(w, http.StatusBadRequest, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
basePath, err := libs.GetOsDir() |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
fullFilePath := filepath.Join(basePath, path) |
||||
|
// 获取文件内容
|
||||
|
fileContent, _, err := r.FormFile("content") |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusBadRequest, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
defer fileContent.Close() |
||||
|
content, err := io.ReadAll(fileContent) |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
// 打开文件,如果不存在则创建
|
||||
|
file, err := os.OpenFile(fullFilePath, os.O_RDWR|os.O_CREATE, 0644) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, "Failed to create file.") |
||||
|
return |
||||
|
} |
||||
|
defer file.Close() |
||||
|
|
||||
|
oldContent, err := io.ReadAll(file) |
||||
|
text := string(oldContent) |
||||
|
//log.Printf("text: %s", text)
|
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
isPwdFile := libs.IsEncryptedFile(text) |
||||
|
|
||||
|
filePwd := r.Header.Get("pwd") |
||||
|
// 获取文件密钥
|
||||
|
fileSecret := libs.GetConfigString("filePwd") |
||||
|
haslink := strings.HasPrefix(string(content), "link::") |
||||
|
//log.Printf("haslink:%v,fileSecret: %s,isPwdFile:%v,filePwd:%s", haslink, fileSecret, isPwdFile, filePwd)
|
||||
|
needPwd := false |
||||
|
if !haslink { |
||||
|
needPwd = true |
||||
|
} |
||||
|
if fileSecret != "" || filePwd != "" { |
||||
|
needPwd = true |
||||
|
} |
||||
|
if isPwdFile { |
||||
|
needPwd = true |
||||
|
} |
||||
|
|
||||
|
// 即不是加密用户又不是加密文件
|
||||
|
if !needPwd { |
||||
|
// 直接写入新内容
|
||||
|
file.Truncate(0) |
||||
|
file.Seek(0, 0) |
||||
|
_, err = file.Write(content) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, "Failed to write file content.") |
||||
|
return |
||||
|
} |
||||
|
CheckAddDesktop(path) |
||||
|
libs.SuccessMsg(w, "", "文件写入成功") |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//log.Printf("fileSecret:%s,filePwd:%s,ispwdfile:%v", fileSecret, filePwd, isPwdFile)
|
||||
|
|
||||
|
// 是加密文件,写入需继续加密
|
||||
|
pwd := "" |
||||
|
if isPwdFile { |
||||
|
//先尝试系统解密
|
||||
|
if fileSecret != "" { |
||||
|
_, err := libs.DecodeFile(fileSecret, text) |
||||
|
if err == nil { |
||||
|
pwd = fileSecret |
||||
|
} |
||||
|
} |
||||
|
//先用户输入解密
|
||||
|
if pwd == "" && filePwd != "" { |
||||
|
_, err := libs.DecodeFile(filePwd, text) |
||||
|
if err == nil { |
||||
|
pwd = filePwd |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
// 不是加密文件,先判断是否有用户输入
|
||||
|
if filePwd != "" { |
||||
|
pwd = filePwd |
||||
|
} else { |
||||
|
// 没有用户输入,则使用系统默认密码
|
||||
|
if fileSecret != "" { |
||||
|
pwd = fileSecret |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if pwd == "" { |
||||
|
libs.Error(w, "文件密码错误", "needPwd") |
||||
|
//log.Printf("pwd is empty, returning error")
|
||||
|
return |
||||
|
} |
||||
|
//log.Printf("pwd: %s", pwd)
|
||||
|
|
||||
|
encryData, err := libs.EncodeFile(pwd, string(content)) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 清空文件内容
|
||||
|
file.Truncate(0) |
||||
|
file.Seek(0, 0) |
||||
|
|
||||
|
_, err = file.Write([]byte(encryData)) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, fmt.Sprintf("文件内容写入失败: %s", err.Error())) |
||||
|
return |
||||
|
} |
||||
|
CheckAddDesktop(path) |
||||
|
libs.SuccessMsg(w, "", "文件写入成功") |
||||
|
/* |
||||
|
//log.Printf("fileData: %s", string(fileData))
|
||||
|
configPwd, ishas := libs.GetConfig("filePwd") |
||||
|
// 如果不是加密文件或者exe文件
|
||||
|
if !ishas || strings.HasPrefix(string(fileData), "link::") { |
||||
|
// 没开启加密,直接明文写入
|
||||
|
_, err := newFile.Write(fileData) |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, "数据写入失败") |
||||
|
return |
||||
|
} |
||||
|
err = CheckAddDesktop(path) |
||||
|
if err != nil { |
||||
|
log.Printf("Error adding file to desktop: %s", err.Error()) |
||||
|
} |
||||
|
libs.SuccessMsg(w, "", "文件写入成功") |
||||
|
return |
||||
|
} else { |
||||
|
// 开启加密后,写入加密数据
|
||||
|
configPwdStr, ok := configPwd.(string) |
||||
|
if !ok { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, "配置文件密码格式错误") |
||||
|
return |
||||
|
} |
||||
|
// 拼接密码和加密后的数据
|
||||
|
passwordPrefix := fmt.Sprintf("@%s@", configPwdStr) |
||||
|
// _, err = newFile.WriteString(fmt.Sprintf("@%s@", configPwdStr))
|
||||
|
// if err != nil {
|
||||
|
// libs.HTTPError(w, http.StatusInternalServerError, "密码写入失败")
|
||||
|
// return
|
||||
|
// }
|
||||
|
entryData, err := libs.EncryptData(fileData, []byte(configPwdStr)) |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, "文件加密失败") |
||||
|
return |
||||
|
} |
||||
|
// 将密码前缀和加密数据拼接成一个完整的字节切片
|
||||
|
completeData := []byte(passwordPrefix + string(entryData)) |
||||
|
// 一次性写入文件
|
||||
|
_, err = newFile.Write(completeData) |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, "文件写入失败") |
||||
|
return |
||||
|
} |
||||
|
err = CheckAddDesktop(path) |
||||
|
if err != nil { |
||||
|
log.Printf("Error adding file to desktop: %s", err.Error()) |
||||
|
} |
||||
|
libs.SuccessMsg(w, "", "文件写入成功") |
||||
|
}*/ |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
func resEncode(w http.ResponseWriter, fileData []byte, filePwd string) { |
||||
|
decryptData, err := libs.DecryptData(fileData[34:], []byte(filePwd)) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//content := base64.StdEncoding.EncodeToString(decryptData)
|
||||
|
if len(decryptData)%8 == 0 { |
||||
|
decryptData = append(decryptData, ' ') |
||||
|
} |
||||
|
// res := libs.APIResponse{Message: "加密文件读取成功", Data: decryptData}
|
||||
|
// json.NewEncoder(w).Encode(res)
|
||||
|
libs.SuccessMsg(w, decryptData, "加密文件读取成功") |
||||
|
} |
||||
|
*/ |
||||
|
func HandleSetFilePwd(w http.ResponseWriter, r *http.Request) { |
||||
|
Pwd := r.Header.Get("Pwd") |
||||
|
if Pwd == "" { |
||||
|
err := libs.DeleteConfig("filePwd") |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, fmt.Sprintf("取消加密失败:%s", err.Error())) |
||||
|
return |
||||
|
} |
||||
|
libs.SuccessMsg(w, nil, "取消加密成功") |
||||
|
return |
||||
|
} |
||||
|
err := libs.SetConfigByName("filePwd", Pwd) |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, err.Error()) |
||||
|
return |
||||
|
} |
||||
|
libs.SuccessMsg(w, nil, "设置密码成功") |
||||
|
} |
@ -1,198 +0,0 @@ |
|||||
package files |
|
||||
|
|
||||
import ( |
|
||||
"fmt" |
|
||||
"godo/libs" |
|
||||
"io" |
|
||||
"log" |
|
||||
"net/http" |
|
||||
"os" |
|
||||
"path/filepath" |
|
||||
"strings" |
|
||||
) |
|
||||
|
|
||||
func HandleWriteFile(w http.ResponseWriter, r *http.Request) { |
|
||||
path := r.URL.Query().Get("path") |
|
||||
if err := validateFilePath(path); err != nil { |
|
||||
libs.HTTPError(w, http.StatusBadRequest, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
basePath, err := libs.GetOsDir() |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
fullFilePath := filepath.Join(basePath, path) |
|
||||
newFile, err := os.Create(fullFilePath) |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
defer newFile.Close() |
|
||||
// 获取文件内容
|
|
||||
fileContent, _, err := r.FormFile("content") |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusBadRequest, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
defer fileContent.Close() |
|
||||
fileData, err := io.ReadAll(fileContent) |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
//log.Printf("fileData: %s", string(fileData))
|
|
||||
configPwd, ishas := libs.GetConfig("filePwd") |
|
||||
// 如果不是加密文件或者exe文件
|
|
||||
if !ishas || strings.HasPrefix(string(fileData), "link::") { |
|
||||
// 没开启加密,直接明文写入
|
|
||||
_, err := newFile.Write(fileData) |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, "数据写入失败") |
|
||||
return |
|
||||
} |
|
||||
err = CheckAddDesktop(path) |
|
||||
if err != nil { |
|
||||
log.Printf("Error adding file to desktop: %s", err.Error()) |
|
||||
} |
|
||||
libs.SuccessMsg(w, "", "文件写入成功") |
|
||||
return |
|
||||
} else { |
|
||||
// 开启加密后,写入加密数据
|
|
||||
configPwdStr, ok := configPwd.(string) |
|
||||
if !ok { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, "配置文件密码格式错误") |
|
||||
return |
|
||||
} |
|
||||
// 拼接密码和加密后的数据
|
|
||||
passwordPrefix := fmt.Sprintf("@%s@", configPwdStr) |
|
||||
// _, err = newFile.WriteString(fmt.Sprintf("@%s@", configPwdStr))
|
|
||||
// if err != nil {
|
|
||||
// libs.HTTPError(w, http.StatusInternalServerError, "密码写入失败")
|
|
||||
// return
|
|
||||
// }
|
|
||||
entryData, err := libs.EncryptData(fileData, []byte(configPwdStr)) |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, "文件加密失败") |
|
||||
return |
|
||||
} |
|
||||
// 将密码前缀和加密数据拼接成一个完整的字节切片
|
|
||||
completeData := []byte(passwordPrefix + string(entryData)) |
|
||||
// 一次性写入文件
|
|
||||
_, err = newFile.Write(completeData) |
|
||||
if err != nil { |
|
||||
libs.HTTPError(w, http.StatusInternalServerError, "文件写入失败") |
|
||||
return |
|
||||
} |
|
||||
err = CheckAddDesktop(path) |
|
||||
if err != nil { |
|
||||
log.Printf("Error adding file to desktop: %s", err.Error()) |
|
||||
} |
|
||||
libs.SuccessMsg(w, "", "文件写入成功") |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func HandleReadFile(w http.ResponseWriter, r *http.Request) { |
|
||||
path := r.URL.Query().Get("path") |
|
||||
if path == "" { |
|
||||
libs.ErrorMsg(w, "文件路径不能为空") |
|
||||
return |
|
||||
} |
|
||||
basePath, err := libs.GetOsDir() |
|
||||
if err != nil { |
|
||||
libs.ErrorMsg(w, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
fullFilePath := filepath.Join(basePath, path) |
|
||||
file, err := os.Open(fullFilePath) |
|
||||
if err != nil { |
|
||||
libs.ErrorMsg(w, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
fileData, err := io.ReadAll(file) |
|
||||
if err != nil { |
|
||||
libs.ErrorMsg(w, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
strData := string(fileData) |
|
||||
//log.Printf("isPwd: %v", strData)
|
|
||||
if strings.HasPrefix(strData, "link::") { |
|
||||
libs.SuccessMsg(w, strData, "文件读取成功") |
|
||||
return |
|
||||
} |
|
||||
// 判断是否为加密文件
|
|
||||
isPwd := IsPwdFile(fileData) |
|
||||
|
|
||||
if !isPwd { |
|
||||
// 未加密文件,直接返回
|
|
||||
//content := base64.StdEncoding.EncodeToString(fileData)
|
|
||||
if len(fileData)%8 == 0 { |
|
||||
fileData = append(fileData, ' ') |
|
||||
} |
|
||||
//log.Printf("fileData: %s", content)
|
|
||||
libs.SuccessMsg(w, fileData, "文件读取成功") |
|
||||
return |
|
||||
} |
|
||||
Pwd := r.Header.Get("Pwd") |
|
||||
filePwd := strData[1:33] |
|
||||
// Pwd为空,info密码与文件密码做比对
|
|
||||
if Pwd == "" { |
|
||||
configPwd, ishas := libs.GetConfig("filePwd") |
|
||||
if !ishas { |
|
||||
libs.Error(w, "未设置密码", "needPwd") |
|
||||
return |
|
||||
} |
|
||||
configPwdStr, ok := configPwd.(string) |
|
||||
if !ok { |
|
||||
libs.Error(w, "后端配置文件密码格式错误", "needPwd") |
|
||||
return |
|
||||
} |
|
||||
// 校验密码
|
|
||||
if filePwd != configPwdStr { |
|
||||
libs.Error(w, "密码错误,请输入正确的密码", "needPwd") |
|
||||
return |
|
||||
} |
|
||||
resEncode(w, fileData, filePwd) |
|
||||
} else { |
|
||||
// Pwd不为空,Pwd与文件密码做比对
|
|
||||
if Pwd != filePwd { |
|
||||
libs.Error(w, "密码错误,请输入正确的密码", "needPwd") |
|
||||
return |
|
||||
} |
|
||||
resEncode(w, fileData, filePwd) |
|
||||
} |
|
||||
} |
|
||||
func resEncode(w http.ResponseWriter, fileData []byte, filePwd string) { |
|
||||
decryptData, err := libs.DecryptData(fileData[34:], []byte(filePwd)) |
|
||||
if err != nil { |
|
||||
libs.ErrorMsg(w, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
//content := base64.StdEncoding.EncodeToString(decryptData)
|
|
||||
if len(decryptData)%8 == 0 { |
|
||||
decryptData = append(decryptData, ' ') |
|
||||
} |
|
||||
// res := libs.APIResponse{Message: "加密文件读取成功", Data: decryptData}
|
|
||||
// json.NewEncoder(w).Encode(res)
|
|
||||
libs.SuccessMsg(w, decryptData, "加密文件读取成功") |
|
||||
} |
|
||||
|
|
||||
func HandleSetFilePwd(w http.ResponseWriter, r *http.Request) { |
|
||||
Pwd := r.Header.Get("Pwd") |
|
||||
if Pwd == "" { |
|
||||
err := libs.DeleteConfig("filePwd") |
|
||||
if err != nil { |
|
||||
libs.ErrorMsg(w, fmt.Sprintf("取消加密失败:%s", err.Error())) |
|
||||
return |
|
||||
} |
|
||||
libs.SuccessMsg(w, nil, "取消加密成功") |
|
||||
return |
|
||||
} |
|
||||
err := libs.SetConfigByName("filePwd", Pwd) |
|
||||
if err != nil { |
|
||||
libs.ErrorMsg(w, err.Error()) |
|
||||
return |
|
||||
} |
|
||||
libs.SuccessMsg(w, nil, "设置密码成功") |
|
||||
} |
|
@ -1,61 +0,0 @@ |
|||||
package files |
|
||||
|
|
||||
import ( |
|
||||
"fmt" |
|
||||
"godo/libs" |
|
||||
"io" |
|
||||
"os" |
|
||||
"testing" |
|
||||
) |
|
||||
|
|
||||
func Test_WriteFile(t *testing.T) { |
|
||||
filePath := "test.txt" |
|
||||
content := "hello world" |
|
||||
configPwd := "b854f92a0bb8462ad75239152081c12b" |
|
||||
file, err := os.Create(filePath) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
defer file.Close() |
|
||||
_, err = file.WriteString(fmt.Sprintf("@%s@", configPwd)) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
encryData, err := libs.EncryptData([]byte(content), []byte(configPwd)) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
_, err = file.Write(encryData) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func Test_ReadFile(t *testing.T) { |
|
||||
filePath := "test.txt" |
|
||||
pwd := "b854f92a0bb8462ad75239152081c12b" |
|
||||
file, err := os.Open(filePath) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
defer file.Close() |
|
||||
data, err := io.ReadAll(file) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
if pwd == "" { |
|
||||
fmt.Println(string(data)) |
|
||||
return |
|
||||
} |
|
||||
realPwd := data[1:33] |
|
||||
if pwd != string(realPwd) { |
|
||||
t.Error("密码错误") |
|
||||
return |
|
||||
} |
|
||||
content := data[34:] |
|
||||
decryData, err := libs.DecryptData(content, []byte(pwd)) |
|
||||
if err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
fmt.Println(string(decryData)) |
|
||||
} |
|
@ -0,0 +1,319 @@ |
|||||
|
package libs |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"crypto/aes" |
||||
|
"crypto/cipher" |
||||
|
"crypto/md5" |
||||
|
"crypto/rand" |
||||
|
"crypto/rsa" |
||||
|
"crypto/sha256" |
||||
|
"crypto/x509" |
||||
|
"encoding/base64" |
||||
|
"encoding/hex" |
||||
|
"fmt" |
||||
|
"io" |
||||
|
"log" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
func GetEncryptedCode(data string) (string, error) { |
||||
|
// 检查是否以 @ 开头
|
||||
|
if !strings.HasPrefix(data, "@") { |
||||
|
return "", fmt.Errorf("invalid input format") |
||||
|
} |
||||
|
// 去掉开头的 @
|
||||
|
data = data[1:] |
||||
|
// 分割加密的私钥和加密的文本
|
||||
|
parts := strings.SplitN(data, "@", 2) |
||||
|
if len(parts) != 2 { |
||||
|
return "", fmt.Errorf("invalid input format") |
||||
|
} |
||||
|
return parts[0], nil |
||||
|
} |
||||
|
func IsEncryptedFile(data string) bool { |
||||
|
if len(data) < 2 { |
||||
|
return false |
||||
|
} |
||||
|
// 检查是否以 @ 开头
|
||||
|
if !strings.HasPrefix(data, "@") { |
||||
|
return false |
||||
|
} |
||||
|
// 去掉开头的 @
|
||||
|
data = data[1:] |
||||
|
// 分割加密的私钥和加密的文本
|
||||
|
parts := strings.SplitN(data, "@", 2) |
||||
|
if len(parts) != 2 { |
||||
|
return false |
||||
|
} |
||||
|
// 检查加密私钥和加密文本是否都不为空
|
||||
|
hexEncodedPrivateKey := parts[0] |
||||
|
// 检查十六进制字符串是否有效
|
||||
|
base64Str, err := hex.DecodeString(hexEncodedPrivateKey) |
||||
|
if err != nil { |
||||
|
return false |
||||
|
} |
||||
|
// 尝试将 Base64 字符串解码为字节切片
|
||||
|
_, err = base64.URLEncoding.DecodeString(string(base64Str)) |
||||
|
return err == nil |
||||
|
} |
||||
|
|
||||
|
// EncodeFile 加密文件
|
||||
|
func EncodeFile(password string, longText string) (string, error) { |
||||
|
privateKey, publicKey, err := GenerateRSAKeyPair(1024) |
||||
|
if err != nil { |
||||
|
fmt.Println("生成RSA密钥对失败:", err) |
||||
|
return "", err |
||||
|
} |
||||
|
// 使用公钥加密
|
||||
|
encryptedText := "" |
||||
|
if len(longText) > 0 { |
||||
|
encryptedText, err = EncryptLongText(longText, publicKey) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("加密失败:%v", err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
pwd, err := hashAndMD5(password) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("加密密码失败:%v", err) |
||||
|
} |
||||
|
encryptedPrivateKey, err := EncryptPrivateKey(privateKey, pwd) |
||||
|
if err != nil { |
||||
|
fmt.Println("加密私钥失败:", err) |
||||
|
return "", fmt.Errorf("加密私钥失败") |
||||
|
} |
||||
|
|
||||
|
// 对 encryptedPrivateKey 进行 Base64 编码
|
||||
|
base64EncryptedPrivateKey := base64.URLEncoding.EncodeToString([]byte(encryptedPrivateKey)) |
||||
|
|
||||
|
// 将 Base64 编码后的字符串转换为十六进制字符串
|
||||
|
hexEncodedPrivateKey := hex.EncodeToString([]byte(base64EncryptedPrivateKey)) |
||||
|
|
||||
|
return "@" + hexEncodedPrivateKey + "@" + encryptedText, nil |
||||
|
} |
||||
|
|
||||
|
// DecodeFile 解密文件
|
||||
|
func DecodeFile(password string, encryptedData string) (string, error) { |
||||
|
// 去掉开头的@
|
||||
|
// log.Printf("encryptedData: %s", encryptedData)
|
||||
|
if !strings.HasPrefix(encryptedData, "@") { |
||||
|
return "", fmt.Errorf("无效的加密数据格式") |
||||
|
} |
||||
|
encryptedData = encryptedData[1:] |
||||
|
|
||||
|
// 分割加密的私钥和加密的文本
|
||||
|
parts := strings.SplitN(encryptedData, "@", 2) |
||||
|
log.Printf("parts:%v", parts) |
||||
|
if len(parts) == 1 { |
||||
|
return "", nil |
||||
|
} |
||||
|
if len(parts) != 2 { |
||||
|
return "", fmt.Errorf("无效的加密数据格式") |
||||
|
} |
||||
|
|
||||
|
hexEncodedPrivateKey := parts[0] |
||||
|
encryptedText := parts[1] |
||||
|
if len(encryptedText) == 0 { |
||||
|
return "", nil |
||||
|
} |
||||
|
|
||||
|
// 将十六进制字符串转换回 Base64 编码字符串
|
||||
|
base64DecodedPrivateKey, err := hex.DecodeString(hexEncodedPrivateKey) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("十六进制字符串解码失败:%v", err) |
||||
|
} |
||||
|
|
||||
|
// 将 Base64 编码字符串解码回原始的 encryptedPrivateKey
|
||||
|
encryptedPrivateKey, err := base64.URLEncoding.DecodeString(string(base64DecodedPrivateKey)) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("Base64字符串解码失败:%v", err) |
||||
|
} |
||||
|
|
||||
|
pwd, err := hashAndMD5(password) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("加密密码失败:%v", err) |
||||
|
} |
||||
|
|
||||
|
// 解密私钥
|
||||
|
privateKey, err := DecryptPrivateKey(string(encryptedPrivateKey), pwd) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("解密私钥失败:%v", err) |
||||
|
} |
||||
|
|
||||
|
// 解密文本
|
||||
|
decryptedText, err := DecryptLongText(encryptedText, privateKey) |
||||
|
if err != nil { |
||||
|
return "", fmt.Errorf("解密文本失败:%v", err) |
||||
|
} |
||||
|
|
||||
|
return decryptedText, nil |
||||
|
} |
||||
|
|
||||
|
// GenerateRSAKeyPair 生成RSA密钥对
|
||||
|
func GenerateRSAKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { |
||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, bits) |
||||
|
if err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
|
||||
|
publicKey := &privateKey.PublicKey |
||||
|
|
||||
|
return privateKey, publicKey, nil |
||||
|
} |
||||
|
func GenertePrivateKey(password string, privateKey *rsa.PrivateKey) (*rsa.PrivateKey, error) { |
||||
|
encryptedPrivateKey, err := EncryptPrivateKey(privateKey, password) |
||||
|
if err != nil { |
||||
|
fmt.Println("加密私钥失败:", err) |
||||
|
return nil, fmt.Errorf("加密私钥失败") |
||||
|
} |
||||
|
decryptedPrivateKey, err := DecryptPrivateKey(encryptedPrivateKey, password) |
||||
|
if err != nil { |
||||
|
fmt.Println("解密私钥失败:", err) |
||||
|
return nil, fmt.Errorf("加密私钥失败") |
||||
|
} |
||||
|
return decryptedPrivateKey, nil |
||||
|
} |
||||
|
|
||||
|
// EncryptWithPublicKey 使用公钥加密数据
|
||||
|
func EncryptWithPublicKey(data []byte, publicKey *rsa.PublicKey) (string, error) { |
||||
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, data, nil) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
return base64.URLEncoding.EncodeToString(ciphertext), nil |
||||
|
} |
||||
|
|
||||
|
// DecryptWithPrivateKey 使用私钥解密数据
|
||||
|
func DecryptWithPrivateKey(encryptedData string, privateKey *rsa.PrivateKey) ([]byte, error) { |
||||
|
ciphertext, err := base64.URLEncoding.DecodeString(encryptedData) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return plaintext, nil |
||||
|
} |
||||
|
|
||||
|
// hashAndMD5 使用 MD5 哈希密码
|
||||
|
func hashAndMD5(password string) (string, error) { |
||||
|
hasher := md5.New() |
||||
|
_, err := hasher.Write([]byte(password)) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
return hex.EncodeToString(hasher.Sum(nil)), nil |
||||
|
} |
||||
|
|
||||
|
// EncryptLongText 使用公钥加密长文本
|
||||
|
func EncryptLongText(longText string, publicKey *rsa.PublicKey) (string, error) { |
||||
|
// 分块加密
|
||||
|
blockSize := publicKey.N.BitLen()/8 - 2*sha256.Size - 2 |
||||
|
chunks := splitIntoChunks([]byte(longText), blockSize) |
||||
|
|
||||
|
var encryptedChunks []string |
||||
|
for _, chunk := range chunks { |
||||
|
encryptedChunk, err := EncryptWithPublicKey(chunk, publicKey) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
encryptedChunks = append(encryptedChunks, encryptedChunk) |
||||
|
} |
||||
|
|
||||
|
return strings.Join(encryptedChunks, ":"), nil |
||||
|
} |
||||
|
|
||||
|
// DecryptLongText 使用私钥解密长文本
|
||||
|
func DecryptLongText(encryptedLongText string, privateKey *rsa.PrivateKey) (string, error) { |
||||
|
// 分块解密
|
||||
|
encryptedChunks := strings.Split(encryptedLongText, ":") |
||||
|
|
||||
|
var decryptedChunks [][]byte |
||||
|
for _, encryptedChunk := range encryptedChunks { |
||||
|
decryptedChunk, err := DecryptWithPrivateKey(encryptedChunk, privateKey) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
decryptedChunks = append(decryptedChunks, decryptedChunk) |
||||
|
} |
||||
|
|
||||
|
return string(bytes.Join(decryptedChunks, nil)), nil |
||||
|
} |
||||
|
|
||||
|
// splitIntoChunks 将数据分割成指定大小的块
|
||||
|
func splitIntoChunks(data []byte, chunkSize int) [][]byte { |
||||
|
var chunks [][]byte |
||||
|
for i := 0; i < len(data); i += chunkSize { |
||||
|
end := i + chunkSize |
||||
|
if end > len(data) { |
||||
|
end = len(data) |
||||
|
} |
||||
|
chunks = append(chunks, data[i:end]) |
||||
|
} |
||||
|
return chunks |
||||
|
} |
||||
|
|
||||
|
// EncryptPrivateKey 使用AES加密RSA私钥
|
||||
|
func EncryptPrivateKey(privateKey *rsa.PrivateKey, password string) (string, error) { |
||||
|
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey) |
||||
|
key := []byte(password) |
||||
|
|
||||
|
block, err := aes.NewCipher(key) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
|
||||
|
gcm, err := cipher.NewGCM(block) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
|
||||
|
nonce := make([]byte, gcm.NonceSize()) |
||||
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
|
||||
|
ciphertext := gcm.Seal(nonce, nonce, privateKeyBytes, nil) |
||||
|
return base64.URLEncoding.EncodeToString(ciphertext), nil |
||||
|
} |
||||
|
|
||||
|
// DecryptPrivateKey 使用AES解密RSA私钥
|
||||
|
func DecryptPrivateKey(encryptedPrivateKey string, password string) (*rsa.PrivateKey, error) { |
||||
|
ciphertext, err := base64.URLEncoding.DecodeString(encryptedPrivateKey) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
key := []byte(password) |
||||
|
|
||||
|
block, err := aes.NewCipher(key) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
gcm, err := cipher.NewGCM(block) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
nonceSize := gcm.NonceSize() |
||||
|
if len(ciphertext) < nonceSize { |
||||
|
return nil, fmt.Errorf("ciphertext too short") |
||||
|
} |
||||
|
|
||||
|
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] |
||||
|
privateKeyBytes, err := gcm.Open(nil, nonce, ciphertext, nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return privateKey, nil |
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
package libs |
||||
|
|
||||
|
import ( |
||||
|
"strings" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
func TestEncodeFile(t *testing.T) { |
||||
|
password := "testpassword" |
||||
|
longText := "This is a test message." |
||||
|
|
||||
|
encryptedData, err := EncodeFile(password, longText) |
||||
|
if err != nil { |
||||
|
t.Fatalf("EncodeFile failed: %v", err) |
||||
|
} |
||||
|
|
||||
|
if !strings.HasPrefix(encryptedData, "@") { |
||||
|
t.Errorf("Encoded data does not start with '@': %s", encryptedData) |
||||
|
} |
||||
|
|
||||
|
parts := strings.SplitN(encryptedData[1:], "@", 2) |
||||
|
if len(parts) != 2 { |
||||
|
t.Errorf("Encoded data format is incorrect: %s", encryptedData) |
||||
|
} |
||||
|
if !IsEncryptedFile(encryptedData) { |
||||
|
t.Errorf("IsEncryptedFile returned false for valid encrypted data: %s", encryptedData) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func TestDecodeFile(t *testing.T) { |
||||
|
password := "96e79218965eb72c92a549dd5a330112" |
||||
|
longText := "This is a test message." |
||||
|
|
||||
|
encryptedData, err := EncodeFile(password, longText) |
||||
|
if err != nil { |
||||
|
t.Fatalf("EncodeFile failed: %v", err) |
||||
|
} |
||||
|
|
||||
|
decryptedText, err := DecodeFile(password, encryptedData) |
||||
|
if err != nil { |
||||
|
t.Fatalf("DecodeFile failed: %v", err) |
||||
|
} |
||||
|
|
||||
|
if decryptedText != longText { |
||||
|
t.Errorf("Decrypted text does not match original: expected '%s', got '%s'", longText, decryptedText) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func TestIsEncryptedFile(t *testing.T) { |
||||
|
password := "testpassword" |
||||
|
longText := "This is a test message." |
||||
|
|
||||
|
encryptedData, err := EncodeFile(password, longText) |
||||
|
if err != nil { |
||||
|
t.Fatalf("EncodeFile failed: %v", err) |
||||
|
} |
||||
|
|
||||
|
if !IsEncryptedFile(encryptedData) { |
||||
|
t.Errorf("IsEncryptedFile returned false for valid encrypted data: %s", encryptedData) |
||||
|
} |
||||
|
|
||||
|
invalidData := "Invalid@Data" |
||||
|
if IsEncryptedFile(invalidData) { |
||||
|
t.Errorf("IsEncryptedFile returned true for invalid encrypted data: %s", invalidData) |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue