UNPKG

relution-sdk

Version:

Relution Software Development Kit for TypeScript and JavaScript

152 lines 16.1 kB
/* * @file core/cipher.ts * Relution SDK * * Created by Thomas Beckmann on 01.07.2016 * Copyright 2016 M-Way Solutions GmbH * * 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. */ /** * @module core */ /** */ "use strict"; var crypto = require('crypto'); var Q = require('q'); var _ = require('lodash'); // key generation parameters var pbkdf2SaltLen = 64; var pbkdf2Iterations = 6911; var pbkdf2KeyLen = 192 / 8; var pbkdf2Digest = 'sha256'; // see https://tools.ietf.org/html/rfc5084 // console.log((<any>crypto).getCiphers()); var cipherAlgorithm = 'aes-192-gcm'; var cipherIvLen = 12; // promised variants var randomBytes = Q.denodeify(crypto.randomBytes); var pbkdf2 = Q.denodeify(crypto.pbkdf2); /** * encrypts a JSON object using a user-provided password. * * This method is suitable for human-entered passwords and not appropriate for machine generated * passwords. Make sure to read regarding pbkdf2. * * @param password of a human. * @param json to encode. * @return encoded json data. * * @internal Not part of public API, exported for library use only. */ function encryptJson(password, json) { return Q.all([ randomBytes(pbkdf2SaltLen), randomBytes(cipherIvLen) ]).spread(function (salt, iv) { return pbkdf2(password, salt, pbkdf2Iterations, pbkdf2KeyLen, pbkdf2Digest).then(function (key) { var cipher = crypto.createCipheriv(cipherAlgorithm, key, iv); var value = cipher.update(JSON.stringify(json), 'utf8', 'base64'); value += cipher.final('base64'); var data = { salt: salt.toString('base64'), iv: iv.toString('base64'), value: value }; var tag = cipher.getAuthTag(); if (tag) { data.tag = tag.toString('base64'); } return data; }); }); } exports.encryptJson = encryptJson; /** * decrypts some encoded json data. * * @param password of a human. * @param data encoded json data. * @return json to decoded. * * @internal Not part of public API, exported for library use only. */ function decryptJson(password, data) { var salt = new Buffer(data.salt, 'base64'); return pbkdf2(password, salt, pbkdf2Iterations, pbkdf2KeyLen, pbkdf2Digest).then(function (key) { var iv = new Buffer(data.iv, 'base64'); var decipher = crypto.createDecipheriv(cipherAlgorithm, key, iv); var tag = data.tag; if (tag) { decipher.setAuthTag(new Buffer(tag, 'base64')); } var value = decipher.update(data.value, 'base64', 'utf8'); value += decipher.final('utf8'); return value; }).then(JSON.parse); } exports.decryptJson = decryptJson; /** * computes a hash of some JSON object synchronously. * * Prefer the async variant if possible. * * @param data to hash. * @param algorithm of choice. * @return hash value. * * @internal Not part of public API, exported for library use only. */ function hashJsonSync(data, algorithm) { var hash = crypto.createHash(algorithm); (function feed(val) { var keys = _.keys(val).sort(); if (keys.length) { hash.update(JSON.stringify(keys), 'utf8'); _.forEach(keys, function (key) { var value = val[key]; if (!_.isUndefined(value)) { if (!_.isObject(value)) { hash.update(JSON.stringify(value), 'utf8'); } else { feed(value); } } }); } })(JSON.parse(JSON.stringify(data))); return hash.digest(); } exports.hashJsonSync = hashJsonSync; /** * computes a hash of some JSON object synchronously. * * @param data to hash. * @param algorithm of choice. * @return hash value. * * @internal Not part of public API, exported for library use only. */ function hashJson(data, algorithm) { return Q.Promise(function (resolve, reject) { try { resolve(hashJsonSync(data, algorithm)); } catch (error) { reject(error); } }); } exports.hashJson = hashJson; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2lwaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvcmUvY2lwaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSDs7R0FFRztBQUNILE1BQU07O0FBRU4sSUFBWSxNQUFNLFdBQU0sUUFBUSxDQUFDLENBQUE7QUFDakMsSUFBWSxDQUFDLFdBQU0sR0FBRyxDQUFDLENBQUE7QUFDdkIsSUFBWSxDQUFDLFdBQU0sUUFBUSxDQUFDLENBQUE7QUFFNUIsNEJBQTRCO0FBQzVCLElBQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQztBQUN6QixJQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQztBQUM5QixJQUFNLFlBQVksR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDO0FBQzdCLElBQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQztBQUU5QiwwQ0FBMEM7QUFDMUMsMkNBQTJDO0FBQzNDLElBQU0sZUFBZSxHQUFHLGFBQWEsQ0FBQztBQUN0QyxJQUFNLFdBQVcsR0FBRyxFQUFFLENBQUM7QUFFdkIsb0JBQW9CO0FBQ3BCLElBQU0sV0FBVyxHQUFHLENBQUMsQ0FBQyxTQUFTLENBQVMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQzVELElBQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxTQUFTLENBQVMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBY2xEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gscUJBQStCLFFBQWdCLEVBQUUsSUFBTztJQUN0RCxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUNYLFdBQVcsQ0FBQyxhQUFhLENBQUM7UUFDMUIsV0FBVyxDQUFDLFdBQVcsQ0FBQztLQUN6QixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQUMsSUFBWSxFQUFFLEVBQVU7UUFDakMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLFlBQVksRUFBRSxZ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XG4gKiBAZmlsZSBjb3JlL2NpcGhlci50c1xuICogUmVsdXRpb24gU0RLXG4gKlxuICogQ3JlYXRlZCBieSBUaG9tYXMgQmVja21hbm4gb24gMDEuMDcuMjAxNlxuICogQ29weXJpZ2h0IDIwMTYgTS1XYXkgU29sdXRpb25zIEdtYkhcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuLyoqXG4gKiBAbW9kdWxlIGNvcmVcbiAqL1xuLyoqICovXG5cbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgUSBmcm9tICdxJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcblxuLy8ga2V5IGdlbmVyYXRpb24gcGFyYW1ldGVyc1xuY29uc3QgcGJrZGYyU2FsdExlbiA9IDY0O1xuY29uc3QgcGJrZGYySXRlcmF0aW9ucyA9IDY5MTE7XG5jb25zdCBwYmtkZjJLZXlMZW4gPSAxOTIgLyA4O1xuY29uc3QgcGJrZGYyRGlnZXN0ID0gJ3NoYTI1Nic7XG5cbi8vIHNlZSBodHRwczovL3Rvb2xzLmlldGYub3JnL2h0bWwvcmZjNTA4NFxuLy8gY29uc29sZS5sb2coKDxhbnk+Y3J5cHRvKS5nZXRDaXBoZXJzKCkpO1xuY29uc3QgY2lwaGVyQWxnb3JpdGhtID0gJ2Flcy0xOTItZ2NtJztcbmNvbnN0IGNpcGhlckl2TGVuID0gMTI7XG5cbi8vIHByb21pc2VkIHZhcmlhbnRzXG5jb25zdCByYW5kb21CeXRlcyA9IFEuZGVub2RlaWZ5PEJ1ZmZlcj4oY3J5cHRvLnJhbmRvbUJ5dGVzKTtcbmNvbnN0IHBia2RmMiA9IFEuZGVub2RlaWZ5PEJ1ZmZlcj4oY3J5cHRvLnBia2RmMik7XG5cbi8qKlxuICogZW5jcnlwdGVkIG9iamVjdCBkYXRhLlxuICpcbiAqIEBpbnRlcm5hbCBOb3QgcGFydCBvZiBwdWJsaWMgQVBJLCBleHBvcnRlZCBmb3IgbGlicmFyeSB1c2Ugb25seS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbmNyeXB0ZWRKc29uPFQ+IHtcbiAgc2FsdDogc3RyaW5nO1xuICBpdjogc3RyaW5nO1xuICB0YWc/OiBzdHJpbmc7XG4gIHZhbHVlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogZW5jcnlwdHMgYSBKU09OIG9iamVjdCB1c2luZyBhIHVzZXItcHJvdmlkZWQgcGFzc3dvcmQuXG4gKlxuICogVGhpcyBtZXRob2QgaXMgc3VpdGFibGUgZm9yIGh1bWFuLWVudGVyZWQgcGFzc3dvcmRzIGFuZCBub3QgYXBwcm9wcmlhdGUgZm9yIG1hY2hpbmUgZ2VuZXJhdGVkXG4gKiBwYXNzd29yZHMuIE1ha2Ugc3VyZSB0byByZWFkIHJlZ2FyZGluZyBwYmtkZjIuXG4gKlxuICogQHBhcmFtIHBhc3N3b3JkIG9mIGEgaHVtYW4uXG4gKiBAcGFyYW0ganNvbiB0byBlbmNvZGUuXG4gKiBAcmV0dXJuIGVuY29kZWQganNvbiBkYXRhLlxuICpcbiAqIEBpbnRlcm5hbCBOb3QgcGFydCBvZiBwdWJsaWMgQVBJLCBleHBvcnRlZCBmb3IgbGlicmFyeSB1c2Ugb25seS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVuY3J5cHRKc29uPFQ+KHBhc3N3b3JkOiBzdHJpbmcsIGpzb246IFQpOiBRLlByb21pc2U8RW5jcnlwdGVkSnNvbjxUPj4ge1xuICByZXR1cm4gUS5hbGwoW1xuICAgIHJhbmRvbUJ5dGVzKHBia2RmMlNhbHRMZW4pLFxuICAgIHJhbmRvbUJ5dGVzKGNpcGhlckl2TGVuKVxuICBdKS5zcHJlYWQoKHNhbHQ6IEJ1ZmZlciwgaXY6IEJ1ZmZlcikgPT4ge1xuICAgIHJldHVybiBwYmtkZjIocGFzc3dvcmQsIHNhbHQsIHBia2RmMkl0ZXJhdGlvbnMsIHBia2RmMktleUxlbiwgcGJrZGYyRGlnZXN0KS50aGVuKChrZXkpID0+IHtcbiAgICAgIGNvbnN0IGNpcGhlciA9IGNyeXB0by5jcmVhdGVDaXBoZXJpdihjaXBoZXJBbGdvcml0aG0sIGtleSwgaXYpO1xuICAgICAgbGV0IHZhbHVlID0gY2lwaGVyLnVwZGF0ZShKU09OLnN0cmluZ2lmeShqc29uKSwgJ3V0ZjgnLCAnYmFzZTY0Jyk7XG4gICAgICB2YWx1ZSArPSBjaXBoZXIuZmluYWwoJ2Jhc2U2NCcpO1xuICAgICAgbGV0IGRhdGE6IEVuY3J5cHRlZEpzb248VD4gPSB7XG4gICAgICAgIHNhbHQ6IHNhbHQudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgICAgICBpdjogaXYudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgICAgICB2YWx1ZTogdmFsdWVcbiAgICAgIH07XG4gICAgICBsZXQgdGFnID0gY2lwaGVyLmdldEF1dGhUYWcoKTtcbiAgICAgIGlmICh0YWcpIHtcbiAgICAgICAgZGF0YS50YWcgPSB0YWcudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIGRlY3J5cHRzIHNvbWUgZW5jb2RlZCBqc29uIGRhdGEuXG4gKlxuICogQHBhcmFtIHBhc3N3b3JkIG9mIGEgaHVtYW4uXG4gKiBAcGFyYW0gZGF0YSBlbmNvZGVkIGpzb24gZGF0YS5cbiAqIEByZXR1cm4ganNvbiB0byBkZWNvZGVkLlxuICpcbiAqIEBpbnRlcm5hbCBOb3QgcGFydCBvZiBwdWJsaWMgQVBJLCBleHBvcnRlZCBmb3IgbGlicmFyeSB1c2Ugb25seS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY3J5cHRKc29uPFQ+KHBhc3N3b3JkOiBzdHJpbmcsIGRhdGE6IEVuY3J5cHRlZEpzb248VD4pOiBRLlByb21pc2U8VD4ge1xuICBjb25zdCBzYWx0ID0gbmV3IEJ1ZmZlcihkYXRhLnNhbHQsICdiYXNlNjQnKTtcbiAgcmV0dXJuIHBia2RmMihwYXNzd29yZCwgc2FsdCwgcGJrZGYySXRlcmF0aW9ucywgcGJrZGYyS2V5TGVuLCBwYmtkZjJEaWdlc3QpLnRoZW4oKGtleSkgPT4ge1xuICAgIGNvbnN0IGl2ID0gbmV3IEJ1ZmZlcihkYXRhLml2LCAnYmFzZTY0Jyk7XG4gICAgY29uc3QgZGVjaXBoZXIgPSBjcnlwdG8uY3JlYXRlRGVjaXBoZXJpdihjaXBoZXJBbGdvcml0aG0sIGtleSwgaXYpO1xuICAgIGxldCB0YWcgPSBkYXRhLnRhZztcbiAgICBpZiAodGFnKSB7XG4gICAgICBkZWNpcGhlci5zZXRBdXRoVGFnKG5ldyBCdWZmZXIodGFnLCAnYmFzZTY0JykpO1xuICAgIH1cbiAgICBsZXQgdmFsdWUgPSBkZWNpcGhlci51cGRhdGUoZGF0YS52YWx1ZSwgJ2Jhc2U2NCcsICd1dGY4Jyk7XG4gICAgdmFsdWUgKz0gZGVjaXBoZXIuZmluYWwoJ3V0ZjgnKTtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH0pLnRoZW4oSlNPTi5wYXJzZSk7XG59XG5cbi8qKlxuICogY29tcHV0ZXMgYSBoYXNoIG9mIHNvbWUgSlNPTiBvYmplY3Qgc3luY2hyb25vdXNseS5cbiAqXG4gKiBQcmVmZXIgdGhlIGFzeW5jIHZhcmlhbnQgaWYgcG9zc2libGUuXG4gKlxuICogQHBhcmFtIGRhdGEgdG8gaGFzaC5cbiAqIEBwYXJhbSBhbGdvcml0aG0gb2YgY2hvaWNlLlxuICogQHJldHVybiBoYXNoIHZhbHVlLlxuICpcbiAqIEBpbnRlcm5hbCBOb3QgcGFydCBvZiBwdWJsaWMgQVBJLCBleHBvcnRlZCBmb3IgbGlicmFyeSB1c2Ugb25seS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc2hKc29uU3luYyhkYXRhOiBhbnksIGFsZ29yaXRobTogc3RyaW5nKTogQnVmZmVyIHtcbiAgY29uc3QgaGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKGFsZ29yaXRobSk7XG4gIChmdW5jdGlvbiBmZWVkKHZhbDogYW55KSB7XG4gICAgY29uc3Qga2V5cyA9IF8ua2V5cyh2YWwpLnNvcnQoKTtcbiAgICBpZiAoa2V5cy5sZW5ndGgpIHtcbiAgICAgIGhhc2gudXBkYXRlKEpTT04uc3RyaW5naWZ5KGtleXMpLCAndXRmOCcpO1xuICAgICAgXy5mb3JFYWNoKGtleXMsIChrZXkpID0+IHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSB2YWxba2V5XTtcbiAgICAgICAgaWYgKCFfLmlzVW5kZWZpbmVkKHZhbHVlKSkge1xuICAgICAgICAgIGlmICghXy5pc09iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGhhc2gudXBkYXRlKEpTT04uc3RyaW5naWZ5KHZhbHVlKSwgJ3V0ZjgnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZmVlZCh2YWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH0pKEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZGF0YSkpKTtcbiAgcmV0dXJuIGhhc2guZGlnZXN0KCk7XG59XG5cbi8qKlxuICogY29tcHV0ZXMgYSBoYXNoIG9mIHNvbWUgSlNPTiBvYmplY3Qgc3luY2hyb25vdXNseS5cbiAqXG4gKiBAcGFyYW0gZGF0YSB0byBoYXNoLlxuICogQHBhcmFtIGFsZ29yaXRobSBvZiBjaG9pY2UuXG4gKiBAcmV0dXJuIGhhc2ggdmFsdWUuXG4gKlxuICogQGludGVybmFsIE5vdCBwYXJ0IG9mIHB1YmxpYyBBUEksIGV4cG9ydGVkIGZvciBsaWJyYXJ5IHVzZSBvbmx5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzaEpzb24oZGF0YTogYW55LCBhbGdvcml0aG06IHN0cmluZyk6IFEuUHJvbWlzZTxCdWZmZXI+IHtcbiAgcmV0dXJuIFEuUHJvbWlzZTxCdWZmZXI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICB0cnkge1xuICAgICAgcmVzb2x2ZShoYXNoSnNvblN5bmMoZGF0YSwgYWxnb3JpdGhtKSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJlamVjdChlcnJvcik7XG4gICAgfVxuICB9KTtcbn1cbiJdfQ==