diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts
index 20dd96f5..d378b51f 100644
--- a/src/@types/global.d.ts
+++ b/src/@types/global.d.ts
@@ -19,6 +19,7 @@ import Store from "electron-store";
 import AutoLaunch from "auto-launch";
 
 import { AppLocalization } from "../language-helper";
+import { StoreData } from "../electron-main";
 
 // global type extensions need to use var for whatever reason
 /* eslint-disable no-var */
@@ -33,13 +34,6 @@ declare global {
         icon_path: string;
         brand: string;
     };
-    var store: Store<{
-        warnBeforeExit?: boolean;
-        minimizeToTray?: boolean;
-        spellCheckerEnabled?: boolean;
-        autoHideMenuBar?: boolean;
-        locale?: string | string[];
-        disableHardwareAcceleration?: boolean;
-    }>;
+    var store: Store<StoreData>;
 }
 /* eslint-enable no-var */
diff --git a/src/electron-main.ts b/src/electron-main.ts
index 4b7a592f..0e3910f9 100644
--- a/src/electron-main.ts
+++ b/src/electron-main.ts
@@ -30,10 +30,10 @@ import { URL } from "url";
 import minimist from "minimist";
 
 import "./ipc";
-import "./keytar";
 import "./seshat";
 import "./settings";
 import * as tray from "./tray";
+import { migrate as migrateSafeStorage } from "./safe-storage";
 import { buildMenuTemplate } from "./vectormenu";
 import webContentsHandler from "./webcontents-handler";
 import * as updater from "./updater";
@@ -252,7 +252,53 @@ async function moveAutoLauncher(): Promise<void> {
     }
 }
 
-global.store = new Store({ name: "electron-config" });
+export interface StoreData {
+    warnBeforeExit: boolean;
+    minimizeToTray: boolean;
+    spellCheckerEnabled: boolean;
+    autoHideMenuBar: boolean;
+    locale?: string | string[];
+    disableHardwareAcceleration: boolean;
+    migratedToSafeStorage: boolean;
+    safeStorage: Record<string, string>;
+}
+
+global.store = new Store({
+    name: "electron-config",
+    schema: {
+        warnBeforeExit: {
+            type: "boolean",
+            default: true,
+        },
+        minimizeToTray: {
+            type: "boolean",
+            default: true,
+        },
+        spellCheckerEnabled: {
+            type: "boolean",
+            default: true,
+        },
+        autoHideMenuBar: {
+            type: "boolean",
+            default: true,
+        },
+        locale: {
+            anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
+        },
+        disableHardwareAcceleration: {
+            type: "boolean",
+            default: false,
+        },
+        migratedToSafeStorage: {
+            type: "boolean",
+            default: false,
+        },
+        safeStorage: {
+            type: "object",
+            additionalProperties: { type: "string" },
+        },
+    },
+}) as Store<StoreData>;
 
 global.appQuitting = false;
 
@@ -345,12 +391,14 @@ app.enableSandbox();
 app.commandLine.appendSwitch("disable-features", "HardwareMediaKeyHandling,MediaSessionService");
 
 // Disable hardware acceleration if the setting has been set.
-if (global.store.get("disableHardwareAcceleration", false) === true) {
+if (global.store.get("disableHardwareAcceleration") === true) {
     console.log("Disabling hardware acceleration.");
     app.disableHardwareAcceleration();
 }
 
 app.on("ready", async () => {
+    await migrateSafeStorage();
+
     let asarPath: string;
 
     try {
@@ -456,7 +504,7 @@ app.on("ready", async () => {
 
         icon: global.trayConfig.icon_path,
         show: false,
-        autoHideMenuBar: global.store.get("autoHideMenuBar", true),
+        autoHideMenuBar: global.store.get("autoHideMenuBar"),
 
         x: mainWindowState.x,
         y: mainWindowState.y,
@@ -477,7 +525,7 @@ app.on("ready", async () => {
     global.mainWindow.webContents.session.setSpellCheckerEnabled(global.store.get("spellCheckerEnabled", true));
 
     // Create trayIcon icon
-    if (global.store.get("minimizeToTray", true)) tray.create(global.trayConfig);
+    if (global.store.get("minimizeToTray")) tray.create(global.trayConfig);
 
     global.mainWindow.once("ready-to-show", () => {
         if (!global.mainWindow) return;
diff --git a/src/ipc.ts b/src/ipc.ts
index b84fb951..f32527ac 100644
--- a/src/ipc.ts
+++ b/src/ipc.ts
@@ -21,7 +21,7 @@ import IpcMainEvent = Electron.IpcMainEvent;
 import { recordSSOSession } from "./protocol";
 import { randomArray } from "./utils";
 import { Settings } from "./settings";
-import { keytar } from "./keytar";
+import { deletePassword, getPassword, setPassword } from "./safe-storage";
 import { getDisplayMediaCallback, setDisplayMediaCallback } from "./displayMediaCallback";
 
 ipcMain.on("setBadgeCount", function (_ev: IpcMainEvent, count: number): void {
@@ -125,7 +125,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
             break;
 
         case "getSpellCheckEnabled":
-            ret = global.store.get("spellCheckerEnabled", true);
+            ret = global.store.get("spellCheckerEnabled");
             break;
 
         case "setSpellCheckLanguages":
@@ -149,12 +149,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
 
         case "getPickleKey":
             try {
-                ret = await keytar?.getPassword("element.io", `${args[0]}|${args[1]}`);
-                // migrate from riot.im (remove once we think there will no longer be
-                // logins from the time of riot.im)
-                if (ret === null) {
-                    ret = await keytar?.getPassword("riot.im", `${args[0]}|${args[1]}`);
-                }
+                ret = await getPassword(`${args[0]}|${args[1]}`);
             } catch (e) {
                 // if an error is thrown (e.g. keytar can't connect to the keychain),
                 // then return null, which means the default pickle key will be used
@@ -165,7 +160,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
         case "createPickleKey":
             try {
                 const pickleKey = await randomArray(32);
-                await keytar?.setPassword("element.io", `${args[0]}|${args[1]}`, pickleKey);
+                await setPassword(`${args[0]}|${args[1]}`, pickleKey);
                 ret = pickleKey;
             } catch (e) {
                 ret = null;
@@ -174,10 +169,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
 
         case "destroyPickleKey":
             try {
-                await keytar?.deletePassword("element.io", `${args[0]}|${args[1]}`);
-                // migrate from riot.im (remove once we think there will no longer be
-                // logins from the time of riot.im)
-                await keytar?.deletePassword("riot.im", `${args[0]}|${args[1]}`);
+                await deletePassword(`${args[0]}|${args[1]}`);
             } catch (e) {}
             break;
         case "getDesktopCapturerSources":
diff --git a/src/keytar.ts b/src/keytar.ts
deleted file mode 100644
index 71380322..00000000
--- a/src/keytar.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-Copyright 2022 New Vector Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import type * as Keytar from "keytar"; // Hak dependency type
-
-let keytar: typeof Keytar | undefined;
-try {
-    // eslint-disable-next-line @typescript-eslint/no-var-requires
-    keytar = require("keytar");
-} catch (e) {
-    if ((<NodeJS.ErrnoException>e).code === "MODULE_NOT_FOUND") {
-        console.log("Keytar isn't installed; secure key storage is disabled.");
-    } else {
-        console.warn("Keytar unexpected error:", e);
-    }
-}
-
-export { keytar };
diff --git a/src/language-helper.ts b/src/language-helper.ts
index 8db65a98..28499d6f 100644
--- a/src/language-helper.ts
+++ b/src/language-helper.ts
@@ -16,8 +16,6 @@ limitations under the License.
 
 import counterpart from "counterpart";
 
-import type Store from "electron-store";
-
 const FALLBACK_LOCALE = "en";
 
 export function _td(text: string): string {
@@ -63,7 +61,7 @@ export function _t(text: string, variables: IVariables = {}): string {
 
 type Component = () => void;
 
-type TypedStore = Store<{ locale?: string | string[] }>;
+type TypedStore = (typeof global)["store"];
 
 export class AppLocalization {
     private static readonly STORE_KEY = "locale";
diff --git a/src/safe-storage.ts b/src/safe-storage.ts
new file mode 100644
index 00000000..48d19dec
--- /dev/null
+++ b/src/safe-storage.ts
@@ -0,0 +1,106 @@
+/*
+Copyright 2022 New Vector Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { safeStorage } from "electron";
+
+import type * as Keytar from "keytar";
+
+const KEYTAR_SERVICE = "element.io";
+const LEGACY_KEYTAR_SERVICE = "riot.im";
+
+let keytar: typeof Keytar | undefined;
+try {
+    // eslint-disable-next-line @typescript-eslint/no-var-requires
+    keytar = require("keytar");
+} catch (e) {
+    if ((<NodeJS.ErrnoException>e).code === "MODULE_NOT_FOUND") {
+        console.log("Keytar isn't installed; secure key storage is disabled.");
+    } else {
+        console.warn("Keytar unexpected error:", e);
+    }
+}
+
+export async function migrate(): Promise<void> {
+    if (global.store.get("migratedToSafeStorage")) return; // already done
+
+    if (keytar) {
+        const credentials = [
+            ...(await keytar.findCredentials(LEGACY_KEYTAR_SERVICE)),
+            ...(await keytar.findCredentials(KEYTAR_SERVICE)),
+        ];
+        credentials.forEach((cred) => {
+            deletePassword(cred.account);
+            setPassword(cred.account, cred.password);
+        });
+    }
+
+    global.store.set("migratedToSafeStorage", true);
+}
+
+/**
+ * Get the stored password for the key.
+ *
+ * @param key The string key name.
+ *
+ * @returns A promise for the password string.
+ */
+export async function getPassword(key: string): Promise<string | null> {
+    if (safeStorage.isEncryptionAvailable()) {
+        const encryptedValue = global.store.get(`safeStorage.${key}`);
+        if (typeof encryptedValue === "string") {
+            return safeStorage.decryptString(Buffer.from(encryptedValue));
+        }
+    }
+    if (keytar) {
+        return (
+            (await keytar.getPassword(KEYTAR_SERVICE, key)) ?? (await keytar.getPassword(LEGACY_KEYTAR_SERVICE, key))
+        );
+    }
+    return null;
+}
+
+/**
+ * Add the password for the key to the keychain.
+ *
+ * @param key The string key name.
+ * @param password The string password.
+ *
+ * @returns A promise for the set password completion.
+ */
+export async function setPassword(key: string, password: string): Promise<void> {
+    if (safeStorage.isEncryptionAvailable()) {
+        const encryptedValue = safeStorage.encryptString(password);
+        global.store.set(`safeStorage.${key}`, encryptedValue.toString());
+    }
+    await keytar?.setPassword(KEYTAR_SERVICE, key, password);
+}
+
+/**
+ * Delete the stored password for the key.
+ *
+ * @param key The string key name.
+ *
+ * @returns A promise for the deletion status. True on success.
+ */
+export async function deletePassword(key: string): Promise<boolean> {
+    if (safeStorage.isEncryptionAvailable()) {
+        global.store.delete(`safeStorage.${key}`);
+        await keytar?.deletePassword(LEGACY_KEYTAR_SERVICE, key);
+        await keytar?.deletePassword(KEYTAR_SERVICE, key);
+        return true;
+    }
+    return false;
+}
diff --git a/src/seshat.ts b/src/seshat.ts
index 9ae970c1..d200e4d4 100644
--- a/src/seshat.ts
+++ b/src/seshat.ts
@@ -25,7 +25,7 @@ import type {
 } from "matrix-seshat"; // Hak dependency type
 import IpcMainEvent = Electron.IpcMainEvent;
 import { randomArray } from "./utils";
-import { keytar } from "./keytar";
+import { getPassword, setPassword } from "./safe-storage";
 
 let seshatSupported = false;
 let Seshat: typeof SeshatType;
@@ -51,19 +51,17 @@ let eventIndex: SeshatType | null = null;
 
 const seshatDefaultPassphrase = "DEFAULT_PASSPHRASE";
 async function getOrCreatePassphrase(key: string): Promise<string> {
-    if (keytar) {
-        try {
-            const storedPassphrase = await keytar.getPassword("element.io", key);
-            if (storedPassphrase !== null) {
-                return storedPassphrase;
-            } else {
-                const newPassphrase = await randomArray(32);
-                await keytar.setPassword("element.io", key, newPassphrase);
-                return newPassphrase;
-            }
-        } catch (e) {
-            console.log("Error getting the event index passphrase out of the secret store", e);
+    try {
+        const storedPassphrase = await getPassword(key);
+        if (storedPassphrase !== null) {
+            return storedPassphrase;
+        } else {
+            const newPassphrase = await randomArray(32);
+            await setPassword(key, newPassphrase);
+            return newPassphrase;
         }
+    } catch (e) {
+        console.log("Error getting the event index passphrase out of the secret store", e);
     }
     return seshatDefaultPassphrase;
 }
diff --git a/src/settings.ts b/src/settings.ts
index 5638cca8..474d2a97 100644
--- a/src/settings.ts
+++ b/src/settings.ts
@@ -36,7 +36,7 @@ export const Settings: Record<string, Setting> = {
     },
     "Electron.warnBeforeExit": {
         async read(): Promise<any> {
-            return global.store.get("warnBeforeExit", true);
+            return global.store.get("warnBeforeExit");
         },
         async write(value: any): Promise<void> {
             global.store.set("warnBeforeExit", value);
@@ -70,7 +70,7 @@ export const Settings: Record<string, Setting> = {
     },
     "Electron.enableHardwareAcceleration": {
         async read(): Promise<any> {
-            return !global.store.get("disableHardwareAcceleration", false);
+            return !global.store.get("disableHardwareAcceleration");
         },
         async write(value: any): Promise<void> {
             global.store.set("disableHardwareAcceleration", !value);