Browse Source

change pwd

master
godo 6 months ago
parent
commit
3ca50aab54
  1. 1147
      frontend/src/components/builtin/FileList.vue
  2. 41
      frontend/src/components/oa/FilePwd.vue
  3. 3
      frontend/src/components/window/IframeFile.vue
  4. 17
      godo/files/pwd.go
  5. 285
      godo/libs/filecode.go
  6. 8
      godo/libs/filecode_test.go

1147
frontend/src/components/builtin/FileList.vue

File diff suppressed because it is too large

41
frontend/src/components/oa/FilePwd.vue

@ -21,12 +21,12 @@
</template>
<script lang="ts" setup>
import { BrowserWindow, useSystem } from "@/system";
import { useSystem } from "@/system";
import { notifyError, notifySuccess } from "@/util/msg";
// import { md5 } from "js-md5";
import { ref } from "vue";
import { getSystemConfig, setSystemKey } from "@/system/config";
const window: BrowserWindow | undefined = inject("browserWindow");
//import { getSystemConfig, setSystemKey } from "@/system/config";
const window: any = inject("browserWindow");
const filePwd = ref("");
const sys = useSystem();
async function setFilePwd() {
@ -47,29 +47,32 @@ async function setFilePwd() {
if (res && res.code == 0) {
notifySuccess("文件密码设置成功");
localStorageFilePwd(path, filePwd.value)
window.close();
// localStorageFilePwd(path, filePwd.value)
} else {
notifyError("文件密码设置失败");
}
//console.log("", res, path);
}else{
notifyError("请输入正确的密码6-10位");
}
}
//
function localStorageFilePwd (path:string, pwd: string) {
if (getSystemConfig().file.isPwd && getSystemConfig().userType == 'person') {
let fileInputPwd = getSystemConfig().fileInputPwd
const pos = fileInputPwd.findIndex((item: any) => item.path == path)
if (pos !== -1) {
fileInputPwd[pos].pwd = pwd
} else {
fileInputPwd.push({
path: path,
pwd: pwd
})
}
setSystemKey('fileInputPwd', fileInputPwd)
}
}
// function localStorageFilePwd (path:string, pwd: string) {
// if (getSystemConfig().file.isPwd && getSystemConfig().userType == 'person') {
// let fileInputPwd = getSystemConfig().fileInputPwd
// const pos = fileInputPwd.findIndex((item: any) => item.path == path)
// if (pos !== -1) {
// fileInputPwd[pos].pwd = pwd
// } else {
// fileInputPwd.push({
// path: path,
// pwd: pwd
// })
// }
// setSystemKey('fileInputPwd', fileInputPwd)
// }
// }
</script>
<style scoped>
.btn-group {

3
frontend/src/components/window/IframeFile.vue

@ -148,6 +148,9 @@ const eventHandler = async (e: MessageEvent) => {
// console.log(title);
title = title.split(SP).pop();
content = toRaw(content);
if(typeof content == "string"){
content = content.trim()
}
if (content && content !== "") {
storeRef.value?.contentWindow?.postMessage(

17
godo/files/pwd.go

@ -5,6 +5,7 @@ import (
"fmt"
"godo/libs"
"io"
"log"
"net/http"
"os"
"path/filepath"
@ -45,9 +46,9 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
if !isPwd {
// 未加密文件,直接返回
text = base64.StdEncoding.EncodeToString(fileData)
// if len(text)%8 == 0 {
// text += " "
// }
if len(text)%8 == 0 {
text += " "
}
//log.Printf("fileData: %s", content)
libs.SuccessMsg(w, text, "文件读取成功")
return
@ -128,21 +129,23 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
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 haslink {
needPwd = false
}
log.Printf("needPwd:%v", needPwd)
// 即不是加密用户又不是加密文件
if !needPwd {
// 直接写入新内容
file.Truncate(0)
file.Seek(0, 0)
log.Printf("write file content%v", content)
_, err = file.Write(content)
if err != nil {
libs.ErrorMsg(w, "Failed to write file content.")

285
godo/libs/filecode.go

@ -1,7 +1,6 @@
package libs
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
@ -13,24 +12,9 @@ import (
"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
@ -41,13 +25,21 @@ func IsEncryptedFile(data string) bool {
}
// 去掉开头的 @
data = data[1:]
// 分割加密的私钥和加密的文本
parts := strings.SplitN(data, "@", 2)
if len(parts) != 2 {
// 分割加密的私钥、二级密码和加密的文本
parts := strings.SplitN(data, "@", 3)
if len(parts) != 3 {
return false
}
// 检查加密私钥和加密文本是否都不为空
hexEncodedPrivateKey := parts[0]
encryptedSecondaryPassword := parts[1]
encryptedText := parts[2]
// 检查各个部分是否都不为空
if hexEncodedPrivateKey == "" || encryptedSecondaryPassword == "" || encryptedText == "" {
return false
}
// 检查十六进制字符串是否有效
base64Str, err := hex.DecodeString(hexEncodedPrivateKey)
if err != nil {
@ -55,25 +47,29 @@ func IsEncryptedFile(data string) bool {
}
// 尝试将 Base64 字符串解码为字节切片
_, err = base64.URLEncoding.DecodeString(string(base64Str))
if err != nil {
return false
}
// 检查二级密码和加密文本是否能被正确解码
_, err = base64.URLEncoding.DecodeString(encryptedSecondaryPassword)
if err != nil {
return false
}
_, err = base64.URLEncoding.DecodeString(encryptedText)
return err == nil
}
// EncodeFile 加密文件
func EncodeFile(password string, longText string) (string, error) {
privateKey, publicKey, err := GenerateRSAKeyPair(1024)
privateKey, publicKey, err := GenerateRSAKeyPair(2048) // 使用2048位密钥更安全
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)
@ -90,33 +86,44 @@ func EncodeFile(password string, longText string) (string, error) {
// 将 Base64 编码后的字符串转换为十六进制字符串
hexEncodedPrivateKey := hex.EncodeToString([]byte(base64EncryptedPrivateKey))
return "@" + hexEncodedPrivateKey + "@" + encryptedText, nil
// 生成二级密码
secondaryPassword, err := GenerateSecondaryPassword(32) // 32字节的二级密码
if err != nil {
return "", err
}
// 使用公钥加密二级密码
encryptedSecondaryPassword, err := EncryptSecondaryPassword(secondaryPassword, publicKey)
if err != nil {
return "", fmt.Errorf("加密二级密码失败:%v", err)
}
// 使用二级密码加密数据
encryptedText, err := EncryptDataWithCBC(longText, secondaryPassword)
if err != nil {
return "", fmt.Errorf("加密数据失败:%v", err)
}
return "@" + hexEncodedPrivateKey + "@" + encryptedSecondaryPassword + "@" + 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 {
// 分割加密的私钥、加密的二级密码和加密的文本
parts := strings.SplitN(encryptedData, "@", 3)
if len(parts) != 3 {
return "", fmt.Errorf("无效的加密数据格式")
}
hexEncodedPrivateKey := parts[0]
encryptedText := parts[1]
if len(encryptedText) == 0 {
return "", nil
}
encryptedSecondaryPassword := parts[1]
encryptedText := parts[2]
// 将十六进制字符串转换回 Base64 编码字符串
base64DecodedPrivateKey, err := hex.DecodeString(hexEncodedPrivateKey)
@ -141,8 +148,14 @@ func DecodeFile(password string, encryptedData string) (string, error) {
return "", fmt.Errorf("解密私钥失败:%v", err)
}
// 解密文本
decryptedText, err := DecryptLongText(encryptedText, privateKey)
// 解密二级密码
secondaryPassword, err := DecryptSecondaryPassword(encryptedSecondaryPassword, privateKey)
if err != nil {
return "", fmt.Errorf("解密二级密码失败:%v", err)
}
// 使用二级密码解密数据
decryptedText, err := DecryptDataWithCBC(encryptedText, secondaryPassword)
if err != nil {
return "", fmt.Errorf("解密文本失败:%v", err)
}
@ -208,54 +221,6 @@ func hashAndMD5(password string) (string, error) {
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)
@ -317,3 +282,139 @@ func DecryptPrivateKey(encryptedPrivateKey string, password string) (*rsa.Privat
return privateKey, nil
}
// DecryptSecondaryPassword 使用私钥解密二级密码
func DecryptSecondaryPassword(encryptedSecondaryPassword string, privateKey *rsa.PrivateKey) (string, error) {
ciphertext, err := base64.URLEncoding.DecodeString(encryptedSecondaryPassword)
if err != nil {
return "", err
}
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil)
if err != nil {
return "", err
}
return string(plaintext), nil
}
// DecodeFileWithSecondaryPassword 解密文件
func DecodeFileWithSecondaryPassword(password string, encryptedData string) (string, error) {
// 去掉开头的@
if !strings.HasPrefix(encryptedData, "@") {
return "", fmt.Errorf("无效的加密数据格式")
}
encryptedData = encryptedData[1:]
// 分割加密的二级密码和加密的文本
parts := strings.SplitN(encryptedData, "@", 2)
if len(parts) != 2 {
return "", fmt.Errorf("无效的加密数据格式")
}
encryptedSecondaryPassword := parts[0]
encryptedText := parts[1]
// 使用私钥解密二级密码
privateKey, err := DecryptPrivateKey(password, password)
if err != nil {
return "", fmt.Errorf("解密私钥失败:%v", err)
}
// 使用私钥解密二级密码
secondaryPassword, err := DecryptSecondaryPassword(encryptedSecondaryPassword, privateKey)
if err != nil {
return "", fmt.Errorf("解密二级密码失败:%v", err)
}
// 使用二级密码解密文本
decryptedText, err := DecryptDataWithCBC(encryptedText, secondaryPassword)
if err != nil {
return "", fmt.Errorf("解密文本失败:%v", err)
}
return decryptedText, nil
}
// GenerateSecondaryPassword 生成一个随机的二级密码
func GenerateSecondaryPassword(length int) (string, error) {
b := make([]byte, length)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
// EncryptWithPublicKey 使用公钥加密二级密码
func EncryptSecondaryPassword(secondaryPassword string, publicKey *rsa.PublicKey) (string, error) {
data := []byte(secondaryPassword)
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, data, nil)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(ciphertext), nil
}
// EncryptDataWithCBC 使用二级密码和CBC模式加密数据
func EncryptDataWithCBC(data, secondaryPassword string) (string, error) {
// 确保 secondaryPassword 长度为 32 字节
if len(secondaryPassword) < 32 {
return "", fmt.Errorf("secondary password too short")
}
key := []byte(secondaryPassword[:32])
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, []byte(data), nil)
return base64.URLEncoding.EncodeToString(ciphertext), nil
}
// DecryptDataWithCBC 使用二级密码和CBC模式解密数据
func DecryptDataWithCBC(encryptedData, secondaryPassword string) (string, error) {
// 确保 secondaryPassword 长度为 32 字节
if len(secondaryPassword) < 32 {
return "", fmt.Errorf("secondary password too short")
}
key := []byte(secondaryPassword[:32])
ciphertext, err := base64.URLEncoding.DecodeString(encryptedData)
if err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return "", fmt.Errorf("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return "", err
}
return string(plaintext), nil
}

8
godo/libs/filecode_test.go

@ -28,7 +28,7 @@ func TestEncodeFile(t *testing.T) {
}
func TestDecodeFile(t *testing.T) {
password := "96e79218965eb72c92a549dd5a330112"
password := "testpassword"
longText := "This is a test message."
encryptedData, err := EncodeFile(password, longText)
@ -42,13 +42,13 @@ func TestDecodeFile(t *testing.T) {
}
if decryptedText != longText {
t.Errorf("Decrypted text does not match original: expected '%s', got '%s'", longText, decryptedText)
t.Errorf("Decrypted text does not match original text. Expected: %v, Got: %v", longText, decryptedText)
}
}
func TestIsEncryptedFile(t *testing.T) {
password := "testpassword"
longText := "This is a test message."
password := "password"
longText := "分地方大幅度"
encryptedData, err := EncodeFile(password, longText)
if err != nil {

Loading…
Cancel
Save