Files
secure-editor-go/main.go
2025-09-13 21:33:40 +08:00

158 lines
3.3 KiB
Go

package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
"os"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
)
const (
AlgorithmAes256Gcm = "aes-256-gcm"
Title = "Secure Editor"
)
func decrypt(ciphertext, key, nonce []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
func encrypt(plaintext, key, nonce []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
return ciphertext, nil
}
func writeFilePreserveMode(filename string, data []byte) error {
fi, err := os.Stat(filename)
if err != nil {
if os.IsNotExist(err) {
return os.WriteFile(filename, data, 0666)
}
return err
}
err = os.WriteFile(filename, data, 0666)
if err != nil {
return err
}
return os.Chmod(filename, fi.Mode())
}
func showErrorMessage(err error, parent fyne.Window) {
dialog.ShowError(err, parent)
}
func main() {
args := os.Args
if len(args) != 5 {
fmt.Printf("Bad encrypt args: %v\n", args)
os.Exit(1)
}
fileName := args[1]
algorithm := args[2]
if algorithm != AlgorithmAes256Gcm {
fmt.Printf("Bad algorithm: %s\n", algorithm)
os.Exit(1)
}
keyBytes, err := hex.DecodeString(args[3])
if err != nil {
fmt.Printf("Bad key: %s, failed: %s\n", args[3], err.Error())
os.Exit(1)
}
if len(keyBytes) != 32 {
fmt.Printf("Bad key length: %d\n", len(keyBytes))
os.Exit(1)
}
nonceBytes, err := hex.DecodeString(args[4])
if err != nil {
fmt.Printf("Bad nonce: %s, failed: %s\n", args[4], err.Error())
os.Exit(1)
}
if len(nonceBytes) != 12 {
fmt.Printf("Bad nonce length: %d\n", len(nonceBytes))
os.Exit(1)
}
fileData, err := os.ReadFile(fileName)
if err != nil {
fmt.Printf("Read file: %s, failed: %s\n", fileName, err.Error())
os.Exit(1)
}
plaintext, err := decrypt(fileData, keyBytes, nonceBytes)
if err != nil {
fmt.Printf("Decrypt file: %s, failed: %s\n", fileName, err.Error())
os.Exit(1)
}
secureEditorApp := app.New()
window := secureEditorApp.NewWindow(Title)
window.Resize(fyne.NewSize(800, 600))
window.SetOnClosed(func() {
secureEditorApp.Quit()
})
textEntry := widget.NewMultiLineEntry()
textEntry.Wrapping = fyne.TextWrapWord
textEntry.SetText(string(plaintext))
exitButton := widget.NewButton(" [ Exit ] ", func() {
secureEditorApp.Quit()
})
saveButton := widget.NewButton(" [ Save ] ", func() {
plaintext := textEntry.Text
ciphertext, err := encrypt([]byte(plaintext), keyBytes, nonceBytes)
if err != nil {
showErrorMessage(err, window)
return
}
err = writeFilePreserveMode(fileName, ciphertext)
if err != nil {
showErrorMessage(err, window)
return
}
secureEditorApp.Quit()
})
content := container.NewBorder(
nil, // top
container.NewBorder(nil, nil, nil, container.NewHBox(exitButton, saveButton), nil), // bottom
nil, // left
nil, // right
textEntry, // center
)
window.SetContent(content)
window.CenterOnScreen()
window.ShowAndRun()
}