1
0
mirror of https://github.com/keeweb/keeweb.git synced 2024-06-21 07:06:39 +02:00
keeweb/desktop/scripts/ipc-handlers/hardware-crypto.js

93 lines
2.8 KiB
JavaScript
Raw Normal View History

const { ipcMain } = require('electron');
2021-01-10 14:31:33 +01:00
const { readXoredValue, makeXoredValue } = require('../util/byte-utils');
const { reqNative } = require('../util/req-native');
2021-04-21 19:31:37 +02:00
const { isDev } = require('../util/app-info');
2021-01-10 14:31:33 +01:00
ipcMain.handle('hardwareCryptoDeleteKey', hardwareCryptoDeleteKey);
ipcMain.handle('hardwareEncrypt', hardwareEncrypt);
ipcMain.handle('hardwareDecrypt', hardwareDecrypt);
const keyTag = 'net.antelle.keeweb.encryption-key';
2021-02-03 20:30:59 +01:00
let testCipherParams;
let keyChecked = false;
2021-02-03 20:30:59 +01:00
async function hardwareCryptoDeleteKey() {
const secureEnclave = reqNative('secure-enclave');
await secureEnclave.deleteKeyPair({ keyTag });
keyChecked = false;
}
2021-01-10 16:56:53 +01:00
async function hardwareEncrypt(e, value) {
return await hardwareCrypto(value, true);
}
async function hardwareDecrypt(e, value, touchIdPrompt) {
return await hardwareCrypto(value, false, touchIdPrompt);
}
async function hardwareCrypto(value, encrypt, touchIdPrompt) {
2021-01-10 14:31:33 +01:00
if (process.platform !== 'darwin') {
throw new Error('Not supported');
}
// This is a native module, but why is it here and not in native-module-host?
2021-01-10 17:11:47 +01:00
// It's because native-module-host is started as a fork,
// and macOS thinks it doesn't have necessary entitlements,
// so any attempt to use Secure Enclave API fails with an error.
2021-01-10 14:31:33 +01:00
const secureEnclave = reqNative('secure-enclave');
const data = readXoredValue(value);
let res;
2021-02-03 20:30:59 +01:00
if (isDev && process.env.KEEWEB_EMULATE_HARDWARE_ENCRYPTION) {
const crypto = require('crypto');
if (!testCipherParams) {
let key, iv;
if (process.env.KEEWEB_EMULATE_HARDWARE_ENCRYPTION === 'persistent') {
key = Buffer.alloc(32, 0);
iv = Buffer.alloc(16, 0);
} else {
key = crypto.randomBytes(32);
iv = crypto.randomBytes(16);
}
testCipherParams = { key, iv };
}
const { key, iv } = testCipherParams;
const algo = 'aes-256-cbc';
let cipher;
if (encrypt) {
cipher = crypto.createCipheriv(algo, key, iv);
} else {
cipher = crypto.createDecipheriv(algo, key, iv);
}
res = Buffer.concat([cipher.update(data), cipher.final()]);
2021-01-10 14:31:33 +01:00
} else {
2021-02-03 20:30:59 +01:00
if (encrypt) {
await checkKey();
res = await secureEnclave.encrypt({ keyTag, data });
} else {
res = await secureEnclave.decrypt({ keyTag, data, touchIdPrompt });
}
2021-01-10 14:31:33 +01:00
}
data.fill(0);
return makeXoredValue(res);
async function checkKey() {
if (keyChecked) {
2021-01-10 14:31:33 +01:00
return;
}
try {
await secureEnclave.createKeyPair({ keyTag });
keyChecked = true;
2021-01-10 14:31:33 +01:00
} catch (e) {
if (!e.keyExists) {
throw e;
}
}
}
2021-01-10 16:56:53 +01:00
}