diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2025-09-23 21:49:08 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2025-09-23 21:49:08 -0700 |
| commit | e3f71dedf3fcbd9e9112880f4b2a442cabd9fba6 (patch) | |
| tree | 0c6f535f6a6e969e47d22504eb1c5530c33902ef /roseh.moe.go | |
| parent | Use pbkdf2 for password hashing instead of sha512 (diff) | |
| download | roseh.moe-e3f71dedf3fcbd9e9112880f4b2a442cabd9fba6.tar.zst | |
Encrypt notepad at rest
Diffstat (limited to 'roseh.moe.go')
| -rw-r--r-- | roseh.moe.go | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/roseh.moe.go b/roseh.moe.go index a15fd9b..e2500ca 100644 --- a/roseh.moe.go +++ b/roseh.moe.go @@ -2,6 +2,8 @@ package main import ( "bytes" + "crypto/aes" + "crypto/cipher" "crypto/ed25519" "crypto/rand" "crypto/subtle" @@ -17,6 +19,7 @@ import ( "os" "path/filepath" "strings" + "sync" "time" "gitlab.com/rhogenson/roseh.moe/internal/pwhash" @@ -35,6 +38,9 @@ var ( notepadPasswordSalt []byte privateKey ed25519.PrivateKey publicKey ed25519.PublicKey + + encryptionKeyMu sync.Mutex + encryptionKey cipher.AEAD ) func loadSecrets() error { @@ -211,7 +217,7 @@ type loginTemplateArgs struct { } func login(w http.ResponseWriter, r *http.Request) { - pwHash, err := pwhash.Hash(r.FormValue("password"), notepadPasswordSalt) + keyBytes, pwHash, err := pwhash.Hash(r.FormValue("password"), notepadPasswordSalt) if err != nil { http.Error(w, fmt.Sprintf("Unable to hash password: %s", err), http.StatusInternalServerError) return @@ -222,6 +228,17 @@ func login(w http.ResponseWriter, r *http.Request) { } return } + block, err := aes.NewCipher(keyBytes) + if err != nil { + http.Error(w, fmt.Sprintf("Could not create AES key: %s", err), http.StatusInternalServerError) + return + } + key, err := cipher.NewGCMWithRandomNonce(block) + encryptionKeyMu.Lock() + if encryptionKey == nil { + encryptionKey = key + } + encryptionKeyMu.Unlock() attachCookie(w) http.Redirect(w, r, r.FormValue("redirect"), http.StatusSeeOther) } @@ -245,11 +262,25 @@ func notepad(w http.ResponseWriter, r *http.Request) { } return } + encryptionKeyMu.Lock() + key := encryptionKey + encryptionKeyMu.Unlock() + if key == nil { + if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: "/notepad"}); err != nil { + log.Printf("Warning: login: %s", err) + } + return + } var currentContent string if currentContentBytes, err := os.ReadFile(*notepadFile); err != nil { currentContent = fmt.Sprintf("Error reading notepad file: %s", err) } else { - currentContent = string(currentContentBytes) + decrypted, err := key.Open(nil, nil, currentContentBytes, nil) + if err != nil { + currentContent = fmt.Sprintf("Could not decrypt notepad contents: %s", err) + } else { + currentContent = string(decrypted) + } } if err := notepadTemplate.Execute(w, notepadTemplateArgs{Content: currentContent, CSRFToken: csrfToken}); err != nil { log.Printf("Warning: notepad: %s", err) @@ -263,12 +294,18 @@ func saveNote(w http.ResponseWriter, r *http.Request) error { if _, ok := cookieAuth(w, r); !ok { return fmt.Errorf("not logged in") } + encryptionKeyMu.Lock() + key := encryptionKey + encryptionKeyMu.Unlock() + if key == nil { + return fmt.Errorf("not logged in") + } f, err := os.CreateTemp(filepath.Dir(*notepadFile), "notepad") if err != nil { return err } defer f.Close() - if _, err = f.Write([]byte(r.FormValue("content"))); err != nil { + if _, err = f.Write(key.Seal(nil, nil, []byte(r.FormValue("content")), nil)); err != nil { return err } if err := f.Close(); err != nil { |
