UNPKG

etkframework

Version:

First test release of Etk over colored coins SDK

174 lines (156 loc) 6.92 kB
/** * Etk Helper library. * == Zero-Knowledge Secure Key Server Storage == * == Host Proof Hosting == * The module uses pbkdf2-sha256 library for SHA256 hash function generation. * * Copyright (C) 2015 Akul Mathur This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Parts of the software are provided under separate licenses, as follows: "colu-nodejs" SDK is under the MIT License "pbkdf2-sha256" is under the BSD License "bip38" is under the MIT License "scryptsy" is under the MIT License "coinstring" is under the MIT License * Core Developer(s): @codecakes Akul Mathur * Maintainer(s): * @codecakes Akul Mathur * Description: * * The expected outcome can be understood by understanding the * Stanford JS Crypto Library for Key Derivation Function. A demo is here: * http://bitwiseshiftleft.github.io/sjcl/demo/ * * Encryption: * The applied process/suggested usage, is like this: * 1. User accesses client app/web UI that can access encrypted string; * 2. User enters password * 3. The local client app/web UI uses a KDF to derive an encryption key from user's password * 4. Client app/web UI decrypts the string using the key. * * Decryption: * Since this Token CC module is "browserify"-ied, * the applied implementation layer that calls this function does the following: * 1. After Client verification via SRP Authentication protocol, the encrypted cipher * is retrieved using the user Password, key and initialization vector stored for the client. * 2. PBKDF uses verification id, IV and a hashed key to decrypt the string to the original key; * 3. Step #2 is repeated to get Seed Key and Address Pvt Key on client side * thus no one but the owner/client has the secure keys. * */ "use strict"; const crypto = require("crypto"), pbkdf2 = require("pbkdf2-sha256"), algorithm = 'aes-256-ctr', randomBytesSize = 16, iterations = 4096, keyLenBytes = 32, HMAC_ALGORITHM = 'SHA256', HMAC_KEY = crypto.randomBytes(32), // This key should be stored in an environment variable hashedLen = function hashedLen (hashed, byteLen) { byteLen = byteLen || 16; for (var x=0, ln = hashed.length; x<32-ln; x++ ) { hashed += (hashed[x]); } return (new Buffer(hashed)).slice(0,byteLen); }, encrypt = function encrypt (password, secret, iv, buf, encryptCB) { /** * @params: * - password: A User supplied password * - secret: The User Credential that needs to be encrypted and stored on server * - encryptCB: A Callback function that works on the result * Should be encryptCB(cipherText, key, iv) * * Usually, this is either the decrypt function OR storage function; * * @Returns: * - cipherText, key, iv, err * err is undefined is operation successful. */ var err; try { const // buf = new Buffer(crypto.randomBytes(randomBytesSize)),//this is the salt // iv = new Buffer(crypto.randomBytes(randomBytesSize)), //use pbkdf2 to derive key key = pbkdf2( password, buf.toString('ascii'), iterations, keyLenBytes ), /** Following can also be used * encryptor.setEncoding('hex'); encryptor.write(plain_text); encryptor.end(); cipher_text = encryptor.read(); */ cipher = crypto.createCipheriv(algorithm, key, iv), cipherText = cipher.update(secret, 'utf8', 'hex') + cipher.final('hex'); /** store buf:iv:cipherText * For eg * encryptCB could use * hashCipherText() function in this module * to store the crypted version of cipherText. * This way the server doesn't know what the cipherText is * to recover the pvt key. */ encryptCB(err, cipherText, iv); } catch (e) { err = e; encryptCB(err, null, null); } }, decrypt = function decrypt (password, buf, cipherText, iv, cbDecrypt) { let err; const key = pbkdf2( password, buf.toString('ascii'), iterations, keyLenBytes ); try { if (cipherText === key && key === iv && iv === null) { throw Error("Null Values"); } const decipher = crypto.createDecipheriv(algorithm, key, iv), //decipherText or usually the pvtkey; decipherText = decipher.update(cipherText, 'hex', 'utf8') + decipher.final('utf8'); cbDecrypt( err, decipherText); } catch (e) { cbDecrypt(err, null); } }, hashCipherText = function hashCipherText (cipherText, password) { const cipher = crypto.createCipher(algorithm, password), crypted = cipher.update(cipherText,'utf8','hex') + cipher.final('hex'); return crypted; }, dehashCipherText = function dehashCipherText (cryptedText, password) { const decipher = crypto.createDecipher(algorithm, password), cipherText = decipher.update(cryptedText,'hex','utf8') + decipher.final('utf8'); return cipherText; }; exports.hashedLen = hashedLen; exports.encrypt = encrypt; exports.decrypt = decrypt; exports.hashCipherText = hashCipherText; exports.dehashCipherText = dehashCipherText; // For testing and debugging purpose only // var password = "breakItDown", // secret = "Scotty too Notty", // buf = new Buffer(crypto.randomBytes(randomBytesSize)),//this is the salt // iv = new Buffer(crypto.randomBytes(randomBytesSize)); // console.log(buf.toString('hex'), iv.toString('hex')); // encrypt(password, secret, iv, buf, function(err, cipherText, iv) { // console.log(cipherText) ; // decrypt(password, buf, cipherText, iv, function(err, decipherText) { // console.log(decipherText); // }); // });