Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/encryption #113

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"javascript-state-machine": "3.1.0",
"jayson": "4.0.0",
"json-pointer": "0.6.2",
"level": "7.0.1",
"level": "^8.0.0",
"lodash.merge": "4.6.2",
"merkletreejs": "0.1.6",
"minsc": "0.2.0",
Expand Down
90 changes: 90 additions & 0 deletions types/encryption.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
var iv = new Uint8Array([188, 185, 57, 146, 246, 194, 116, 34, 12, 80, 198, 76]);
var textEnc = new TextEncoder();
var textDec = new TextDecoder("utf-8");

/**
* Encryption functionality using SubtleCrypto algorithm
*/

export const importKey = () => {
return window.crypto.subtle.importKey(
"jwk", //can be "jwk" or "raw"
{ //this is an example jwk key, "raw" would be an ArrayBuffer
kty: "oct",
k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE",
alg: "A256GCM",
ext: true,
},
{ //this is the algorithm options
name: "AES-GCM",
},
false, //whether the key is extractable (i.e. can be used in exportKey)
["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey"
)
}

export const generateKey = () => {
return window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256, //can be 128, 192, or 256
},
true, //whether the key is extractable (i.e. can be used in exportKey)
["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey"
)
}

export const encrypt = (data, key, iv) => {
return window.crypto.subtle.encrypt(
{
name: "AES-GCM",

//Don't re-use initialization vectors!
//Always generate a new iv every time your encrypt!
//Recommended to use 12 bytes length
iv: iv,

//Additional authentication data (optional)
// additionalData: ArrayBuffer,

//Tag length (optional)
tagLength: 128, //can be 32, 64, 96, 104, 112, 120 or 128 (default)
},
key, //from generateKey or importKey above
data //ArrayBuffer of data you want to encrypt
);
}

export const decrypt = (data, key, iv) => {
return window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv, //The initialization vector you used to encrypt
//additionalData: ArrayBuffer, //The addtionalData you used to encrypt (if any)
tagLength: 128, //The tagLength you used to encrypt (if any)
},
key, //from generateKey or importKey above
data //ArrayBuffer of the data
)
}

export const encryptToString = async (data) => {
data = textEnc.encode(data);
let key = await importKey();
let result = new Uint8Array(await encrypt(data, key, iv));
let res = '';
for (let i = 0; i < result.length; i++)
res += String.fromCharCode(result[i]);

return res;
}

export const decryptFromString = async (data) => {
let key = await importKey();
let buffer = new Uint8Array(data.length);
for (let i = 0; i < data.length; i++) {
buffer[i] = data.charCodeAt(i);
}

return textDec.decode(await decrypt(buffer, key, iv));
}
4 changes: 2 additions & 2 deletions types/keystore.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

// Dependencies
const level = require('level');
const { Level } = require('level');
const merge = require('lodash.merge');
const monitor = require('fast-json-patch');
const pointer = require('json-pointer');
Expand Down Expand Up @@ -131,7 +131,7 @@ class Keystore extends Actor {
}

try {
keystore.db = level(keystore.settings.path, {
keystore.db = new Level(keystore.settings.path, {
keyEncoding: keystore.codec,
valueEncoding: keystore.codec
}, _handleDiskOpen.bind(keystore));
Expand Down
174 changes: 172 additions & 2 deletions types/store.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

// Dependencies
const level = require('level');
const { Level } = require('level');
const crypto = require('crypto');
const pointer = require('json-pointer');

Expand Down Expand Up @@ -390,7 +390,7 @@ class Store extends Actor {
// if (this.db) return this;

try {
this.db = level(this.settings.path);
this.db = new Level(this.settings.path);
this.trust(this.db);
this.status = 'opened';
await this.commit();
Expand Down Expand Up @@ -569,6 +569,176 @@ class Store extends Actor {

return this;
}



/**
*
* Functions for leveldb store
*
*/


/**
* Create new leveldb store
* @param {String} dbName Name to use for database.
*/
async createDB (dbName) {
this.exdb = new Level(dbName);
this.accountTB = this.exdb.sublevel('account', { valueEncoding: 'json' });
this.settingTB = this.exdb.sublevel('setting', { valueEncoding: 'json' });
}

/**
* Initialize leveldb with chain flags set to true
*/
async initDB () {
//Initialize Chains Toggle
this.settingTB.put('chains', [true, true, true, true, true]);
}

/**
* Clear database in the store
*/
clearDatabase () {
this.accountTB.clear();
};

/**
* Set seed phrase to setting
* @param {Array<string>} phrase 12 seed phrases
*/
async setSeedPhrase (phrase) {
this.settingTB.put('phrase', phrase);
};


/**
* Insert account into store.
* @param {IAccount} account IAccount type for setting.
*/
async insertAccount (account) {
let accountCount = 0;

for await (const [key, value] of this.accountTB.iterator()) {
accountCount++;
}

this.accountTB.put(accountCount, account);
}


/**
* Insert identity into store of specified account index.
* @param {IIdentity} identity array of identities generated from account.
* @param {number} accountId account index generated from seed.
*/
async insertIdentity (identity, accountId) {
const account = await this.accountTB.get(accountId);
// @ts-ignore

var length = account.identity.length;

account.identity[length] = identity;
// @ts-ignore
this.accountTB.put(accountId, account);
}


/**
* Enable/disable chain operability for specified idenity
* @param {number} accountId Account index.
* @param {number} identity identity index.
* @param {number} chain chain's id listed in browser extension.
* @param {boolean} state boolean to enable or disable chain.
*/
async setDBIdentityCheckState (accountId, identity, chain, state) {
const account = await this.accountTB.get(accountId);

account.identity[identity][chain].allowed = state;

this.accountTB.put(accountId, account);
}

/**
* Enable/disable chain operability for wallet
* @param {Array} settings Chain Settings
*/
async setGlobalChainState (settings) {
this.settingTB.put('chains', settings);
};

/**
* Check if there is an account in the store
*/
async getAccountValid () {
let accountCount = 0;

for await (const [key, value] of this.accountTB.iterator()) {
accountCount++;
}

return accountCount !== 0;
}

/**
* Get global chain state
*/
async getGlobalChainState () {
const settings = await this.settingTB.get('chains', { valueEncoding: this.exdb.valueEncoding('json') });
return settings;
}

/**
* Get specific account from the store
* @param {number} accountId Account Index
*/
async getAccount (accountId) {
const account = await this.accountTB.get(accountId, { valueEncoding: this.exdb.valueEncoding('json') });
return account;
}

/**
* Check if the password inputed is same as saved in the store
* @param {number} accountId Account Index
* @param {string} passHash Hashed Password
*/
async checkPassword (accountId, passHash) {
const res = await this.accountTB.get(accountId);
// @ts-ignore
return (res.password === passHash);
}

/**
* Change the password in the store
* @param {number} accountId Account Index
* @param {string} password Hashed Password
*/
async changePassword (accountId, password) {
const account = await this.accountTB.get(accountId);
account.password = password;
this.accountTB.put(accountId, account);
}

/**
* Retrieves private key of account in the store
* @param {number} accountId Account Index
*/
async retrievePrivateKey (accountId) {
const res = await this.accountTB.get(accountId);
return res.privateKey;
};

/**
* Get Count of identities of an account
* @param {number} accountId Account Index
*/
async getIdentityCount (accountId) {
const res = await this.accountTB.get(accountId);
// @ts-ignore
return res.identity.length;
}

}

module.exports = Store;