security: random persisted fallback key for EncryptedStore (not the userData path) - #21
Merged
Merged
Conversation
… the userData path When Electron safeStorage (OS keychain) is unavailable, EncryptedStore fell back to AES-256-GCM with a key derived from the userData path (pbkdf2(userDataPath, fixed-salt)). Both inputs are predictable, so anyone able to read the store file could recompute the key and decrypt it — the encryption gave no real confidentiality. - New src/main/utils/encrypted-store-crypto.ts (pure, unit-tested): gcmEncrypt/ gcmDecrypt, deriveKeyFromPath (kept only to read old data), and getOrCreateRandomKey which persists a random 32-byte key with owner-only (0600) permissions. - Fallback encryption now uses the random key and tags entries keyId:'random'; reads pick the key by keyId (absent → legacy path key), so existing path-key data still decrypts — no data loss, no migration needed. Tests: encrypted-store-crypto.test.ts — round-trip, wrong-key rejection, key persistence, 0600 perms, legacy backward-compat. Full suite green, tsc clean. (The fallback only triggers without an OS keychain — an edge case, but the key was the store's only secret.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Was
Der AES-Fallback von
EncryptedStore(wenn kein OS-Keychain verfügbar ist) nutzt jetzt einen zufälligen, persistierten Schlüssel statt eines vom userData-Pfad abgeleiteten.Warum
Der Fallback leitete den Schlüssel aus
pbkdf2(userDataPath, fixes-Salt)ab — beide Eingaben sind vorhersehbar. Wer die Store-Datei lesen kann, kann den Schlüssel nachrechnen und entschlüsseln → die „Verschlüsselung" bot keine echte Vertraulichkeit. Audit: Low (crypto).Änderungen
src/main/utils/encrypted-store-crypto.ts(rein, unit-getestet):gcmEncrypt/gcmDecrypt,deriveKeyFromPath(nur noch zum Lesen alter Daten) undgetOrCreateRandomKey— persistiert einen zufälligen 32-Byte-Schlüssel mit 0600-Rechten.keyId:'random'; Reads wählen den Schlüssel perkeyId(fehlt → Legacy-Pfad-Key). Bestandsdaten entschlüsseln weiter — kein Datenverlust, keine Migration nötig.Tests
encrypted-store-crypto.test.ts(rot vor Modul): Round-Trip, Falsch-Key-Ablehnung (Auth-Tag), Key-Persistenz, 0600-Rechte, Legacy-Rückwärtskompatibilität. Volle Suite grün,tsc -p tsconfig.main.jsonclean.Review-Punkte
<store>.key(0600) neben dem Store. Wer Dateizugriff hat, hat beide — aber der Angreifer braucht jetzt Dateizugriff, nicht bloss Kenntnis des Pfads. Für echte Vertraulichkeit ohne Keychain gibt es keine reine Softwarelösung; das ist die pragmatische Härtung.Dokumentation
Security-Audit (2026-08-21), Mingly Low-Finding (crypto / EncryptedStore).
🤖 Generated with Claude Code