Use security module

This commit is contained in:
Jiiks 2018-08-13 12:33:44 +03:00
parent 0c0ebb2ebb
commit 5592a8d376
3 changed files with 46 additions and 15 deletions

View File

@ -17,7 +17,6 @@ import { request } from 'vendor';
import { Utils } from 'common';
import E2EEComponent from './E2EEComponent.vue';
import E2EEMessageButton from './E2EEMessageButton.vue';
import aes256 from 'aes256';
const TEMP_KEY = 'temporarymasterkey';
let seed;
@ -31,7 +30,7 @@ export default new class E2EE extends BuiltinModule {
setMaster(key) {
seed = Security.randomBytes();
const newMaster = this.encrypt(seed, key);
const newMaster = Security.encrypt(seed, key);
// TODO re-encrypt everything with new master
return (this.master = newMaster);
}
@ -45,17 +44,22 @@ export default new class E2EE extends BuiltinModule {
}
encrypt(key, content, prefix = '') {
if (!key) {
// Encrypt something with master
return Security.encrypt(Security.decrypt(seed, this.master), content);
}
if (!content) {
// Get key for current channel and encrypt
const haveKey = this.getKey(DiscordApi.currentChannel.id);
if (!haveKey) return 'nokey';
return this.encrypt(this.decrypt(this.decrypt(seed, this.master), haveKey), key);
return Security.encrypt(Security.decrypt(seed, [this.master, haveKey]), key);
}
return prefix + aes256.encrypt(key, content);
return prefix + Security.encrypt(key, content);
}
decrypt(key, content, prefix = '') {
return aes256.decrypt(key, content.replace(prefix, ''));
return Security.decrypt(key, content, prefix);
}
async createHmac(data) {
@ -71,9 +75,10 @@ export default new class E2EE extends BuiltinModule {
}
async enabled(e) {
window._sec = Security;
seed = Security.randomBytes();
// TODO Input modal for key
this.master = this.encrypt(seed, TEMP_KEY);
this.master = Security.encrypt(seed, TEMP_KEY);
this.patchMessageContent();
const selector = '.' + WebpackModules.getClassName('channelTextArea', 'emojiButton');
@ -106,7 +111,7 @@ export default new class E2EE extends BuiltinModule {
if (!content.startsWith('$:')) return; // Not an encrypted string
let decrypt;
try {
decrypt = this.decrypt(this.decrypt(this.decrypt(seed, this.master), key), component.props.message.content);
decrypt = Security.decrypt(seed, [this.master, key, component.props.message.content]);
} catch (err) { return } // Ignore errors such as non empty
component.props.message.bd_encrypted = true;
@ -121,7 +126,11 @@ export default new class E2EE extends BuiltinModule {
renderMessageContent(component, args, retVal) {
if (!component.props.message.bd_encrypted) return;
try {
retVal.props.children[0].props.children.props.children.props.children.unshift(VueInjector.createReactElement(E2EEMessageButton));
} catch (err) {
Logger.err('E2EE', err.message);
}
}
beforeRenderImageWrapper(component, args, retVal) {
@ -145,7 +154,7 @@ export default new class E2EE extends BuiltinModule {
}
Logger.info('E2EE', 'Returning encrypted image from cache');
try {
const decrypt = this.decrypt(this.decrypt(this.decrypt(seed, this.master), haveKey), cached.image);
const decrypt = Security.decrypt(seed, [this.master, haveKey, cached.image]);
component.props.className = 'bd-decryptedImage';
component.props.src = component.props.original = 'data:;base64,' + decrypt;
} catch (err) { return } finally { component.props.readyState = 'READY' }
@ -207,7 +216,7 @@ export default new class E2EE extends BuiltinModule {
handleChannelTextAreaSubmit(component, args, retVal) {
const key = this.getKey(DiscordApi.currentChannel.id);
if (!this.encryptNewMessages || !key) return;
component.props.value = this.encrypt(this.decrypt(this.decrypt(seed, this.master), key), component.props.value, '$:');
component.props.value = Security.encrypt(Security.decrypt(seed, [this.master, key]), component.props.value, '$:');
}
async disabled(e) {

View File

@ -14,16 +14,20 @@ import aes256 from 'aes256';
export default class Security {
static encrypt(key, content, prefix = '') {
if (key instanceof Array) return this.deepEncrypt(key, content, prefix);
if (key instanceof Array || content instanceof Array) return this.deepEncrypt(key, content, prefix);
return `${prefix}${aes256.encrypt(key, content)}`;
}
static decrypt(key, content, prefix = '') {
if (key instanceof Array) return this.deepDecrypt(key, content, prefix);
if (key instanceof Array || content instanceof Array) {
console.log('deep decrypting');
return this.deepDecrypt(key, content, prefix);
}
return aes256.decrypt(key, content.replace(prefix, ''));
}
static deepEncrypt(keys, content, prefix = '') {
if (content && content instanceof Array) return this.deepEncryptContent(keys, content, prefix);
let encrypt = null;
for (const key of keys) {
if (encrypt === null) encrypt = this.encrypt(key, content, prefix);
@ -32,7 +36,17 @@ export default class Security {
return encrypt;
}
static deepEncryptContent(key, contents, prefix = '') {
let encrypt = null;
for (const content of contents) {
if (encrypt === null) encrypt = this.encrypt(key, content, prefix);
else encrypt = this.encrypt(encrypt, content, prefix);
}
return encrypt;
}
static deepDecrypt(keys, content, prefix = '') {
if (content && content instanceof Array) return this.deepDecryptContent(keys, content, prefix);
let decrypt = null;
for (const key of keys.reverse()) {
if (decrypt === null) decrypt = this.decrypt(key, content, prefix);
@ -41,6 +55,15 @@ export default class Security {
return decrypt;
}
static deepDecryptContent(key, contents, prefix = '') {
let decrypt = null;
for (const content of contents) {
if (decrypt === null) decrypt = this.decrypt(key, content, prefix);
else decrypt = this.decrypt(decrypt, content, prefix);
}
return decrypt;
}
static randomBytes(length = 64, to = 'hex') {
return nodecrypto.randomBytes(length).toString(to);
}

View File

@ -22,13 +22,12 @@
</template>
<script>
import aes256 from 'aes256';
import { DiscordApi } from 'modules';
import { E2EE } from 'builtin';
export default {
data() {
return {
masterKey: 'temporarymasterkey',
valueChanged: false
}
},
@ -42,7 +41,7 @@
},
valueBlur(e) {
if (!this.valueChanged) return;
const value = aes256.encrypt(this.masterKey, e.target.value);
const value = E2EE.encrypt(null, e.target.value);
this.setting.value = { key: this.setting.value.key, value }
this.valueChanged = false;
},