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