@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
409 lines (355 loc) • 15.7 kB
JavaScript
import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys";
import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols";
import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor";
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors";
import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties";
import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property";
import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty";
import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator";
import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator";
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); if (enumerableOnly) symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context6; _forEachInstanceProperty(_context6 = ownKeys(Object(source), true)).call(_context6, function (key) { _defineProperty(target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors) { _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)); } else { var _context7; _forEachInstanceProperty(_context7 = ownKeys(Object(source))).call(_context7, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } } return target; }
import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import nacl from 'tweetnacl';
import { v4 as uuid } from 'uuid';
import { encodeBase58Check } from './crypto';
import { isBase64, isHex } from './string';
var _sodium = require('libsodium-wrappers-sumo');
/**
* KeyStore module
* @module @aeternity/aepp-sdk/es/utils/keystore
* @example import { Keystore } from '@aeternity/aepp-sdk'
* @example const { Keystore } = require('@aeternity/aepp-sdk')
*/
var DEFAULTS = {
crypto: {
secret_type: 'ed25519',
symmetric_alg: 'xsalsa20-poly1305',
kdf: 'argon2id',
kdf_params: {
memlimit_kib: 65536,
opslimit: 3,
parallelism: 1
}
}
}; // DERIVED KEY PART
var DERIVED_KEY_FUNCTIONS = {
argon2id: deriveKeyUsingArgon2id
};
export function deriveKeyUsingArgon2id(_x, _x2, _x3) {
return _deriveKeyUsingArgon2id.apply(this, arguments);
} // CRYPTO PART
function _deriveKeyUsingArgon2id() {
_deriveKeyUsingArgon2id = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(password, salt, options) {
var _options$kdf_params, memoryCost, timeCost;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_options$kdf_params = options.kdf_params, memoryCost = _options$kdf_params.memlimit_kib, timeCost = _options$kdf_params.opslimit; // const isBrowser = !(typeof module !== 'undefined' && module.exports)
return _context2.abrupt("return", _sodium.ready.then( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
var sodium, result;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
// tslint:disable-next-line:typedef
sodium = _sodium;
result = sodium.crypto_pwhash(32, password, salt, timeCost, memoryCost * 1024, sodium.crypto_pwhash_ALG_ARGON2ID13);
return _context.abrupt("return", Buffer.from(result));
case 3:
case "end":
return _context.stop();
}
}
}, _callee);
}))));
case 2:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
return _deriveKeyUsingArgon2id.apply(this, arguments);
}
var CRYPTO_FUNCTIONS = {
'xsalsa20-poly1305': {
encrypt: encryptXsalsa20Poly1305,
decrypt: decryptXsalsa20Poly1305
}
};
function encryptXsalsa20Poly1305(_ref) {
var plaintext = _ref.plaintext,
key = _ref.key,
nonce = _ref.nonce;
return nacl.secretbox(plaintext, nonce, key);
}
function decryptXsalsa20Poly1305(_ref2) {
var ciphertext = _ref2.ciphertext,
key = _ref2.key,
nonce = _ref2.nonce;
var res = nacl.secretbox.open(ciphertext, nonce, key);
if (!res) throw new Error('Invalid password or nonce');
return res;
}
/**
* Convert a string to a Buffer. If encoding is not specified, hex-encoding
* will be used if the input is valid hex. If the input is valid base64 but
* not valid hex, base64 will be used. Otherwise, utf8 will be used.
* @param {string} str String to be converted.
* @param {string=} enc Encoding of the input string (optional).
* @return {buffer} Buffer (bytearray) containing the input data.
*/
function str2buf(str, enc) {
if (!str || str.constructor !== String) return str;
if (!enc && isHex(str)) enc = 'hex';
if (!enc && isBase64(str)) enc = 'base64';
return Buffer.from(str, enc);
}
/**
* Symmetric private key encryption using secret (derived) key.
* @param {buffer|string} plaintext Data to be encrypted.
* @param {buffer|string} key Secret key.
* @param {buffer|string} nonce Randomly generated nonce.
* @param {string=} algo Encryption algorithm (default: DEFAULTS.crypto.symmetric_alg).
* @return {buffer} Encrypted data.
*/
function encrypt(plaintext, key, nonce) {
var algo = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : DEFAULTS.crypto.symmetric_alg;
if (!CRYPTO_FUNCTIONS[algo]) throw new Error(algo + ' is not available');
return CRYPTO_FUNCTIONS[algo].encrypt({
plaintext: plaintext,
nonce: nonce,
key: key
});
}
/**
* Symmetric private key decryption using secret (derived) key.
* @param {buffer|Uint8Array} ciphertext Data to be decrypted.
* @param {buffer|Uint8Array} key Secret key.
* @param {buffer|Uint8Array} nonce Nonce from key-object.
* @param {string=} algo Encryption algorithm.
* @return {buffer} Decrypted data.
*/
function decrypt(ciphertext, key, nonce, algo) {
if (!CRYPTO_FUNCTIONS[algo]) throw new Error(algo + ' is not available');
return CRYPTO_FUNCTIONS[algo].decrypt({
ciphertext: ciphertext,
nonce: nonce,
key: key
});
}
/**
* Derive secret key from password with key derivation function.
* @param {string} password User-supplied password.
* @param {buffer|Uint8Array} nonce Randomly generated nonce.
* @param {Object=} options Encryption parameters.
* @param {string=} options.kdf Key derivation function (default: DEFAULTS.crypto.kdf).
* @param {Object=} options.kdf_params KDF parameters (default: DEFAULTS.crypto.kdf_params).
* @return {buffer} Secret key derived from password.
*/
function deriveKey(_x4, _x5) {
return _deriveKey.apply(this, arguments);
}
/**
* Assemble key data object in secret-storage format.
* @param {buffer} name Key name.
* @param {buffer} derivedKey Password-derived secret key.
* @param {buffer} privateKey Private key.
* @param {buffer} nonce Randomly generated 24byte nonce.
* @param {buffer} salt Randomly generated 16byte salt.
* @param {Object=} options Encryption parameters.
* @param {string=} options.kdf Key derivation function (default: argon2id).
* @param {string=} options.cipher Symmetric cipher (default: constants.cipher).
* @param {Object=} options.kdf_params KDF parameters (default: constants.<kdf>).
* @return {Object}
*/
function _deriveKey() {
_deriveKey = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(password, nonce) {
var options,
_args3 = arguments;
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
options = _args3.length > 2 && _args3[2] !== undefined ? _args3[2] : {
kdf_params: DEFAULTS.crypto.kdf_params,
kdf: DEFAULTS.crypto.kdf
};
if (!(typeof password === 'undefined' || password === null || !nonce)) {
_context3.next = 3;
break;
}
throw new Error('Must provide password and nonce to derive a key');
case 3:
if (Object.prototype.hasOwnProperty.call(DERIVED_KEY_FUNCTIONS, options.kdf)) {
_context3.next = 5;
break;
}
throw new Error('Unsupported kdf type');
case 5:
return _context3.abrupt("return", DERIVED_KEY_FUNCTIONS[options.kdf](password, nonce, options));
case 6:
case "end":
return _context3.stop();
}
}
}, _callee3);
}));
return _deriveKey.apply(this, arguments);
}
function marshal(name, derivedKey, privateKey, nonce, salt) {
var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
var opt = _Object$assign({}, DEFAULTS.crypto, options);
return _Object$assign({
name: name,
version: 1,
public_key: getAddressFromPriv(privateKey),
id: uuid()
}, {
crypto: _Object$assign({
secret_type: opt.secret_type,
symmetric_alg: opt.symmetric_alg,
ciphertext: Buffer.from(encrypt(Buffer.from(privateKey), derivedKey, nonce, opt.symmetric_alg)).toString('hex'),
cipher_params: {
nonce: Buffer.from(nonce).toString('hex')
}
}, {
kdf: opt.kdf,
kdf_params: _objectSpread(_objectSpread({}, opt.kdf_params), {}, {
salt: Buffer.from(salt).toString('hex')
})
})
});
}
export function getAddressFromPriv(secret) {
var keys = nacl.sign.keyPair.fromSecretKey(str2buf(secret));
var publicBuffer = Buffer.from(keys.publicKey);
return "ak_".concat(encodeBase58Check(publicBuffer));
}
/**
* Recover plaintext private key from secret-storage key object.
* @param {String} password Keystore object password.
* @param {Object} keyObject Keystore object.
* @return {Buffer} Plaintext private key.
*/
export function recover(_x6, _x7) {
return _recover.apply(this, arguments);
}
/**
* Export private key to keystore secret-storage format.
* @param {String} name Key name.
* @param {String} password User-supplied password.
* @param {String} privateKey Private key.
* @param {Buffer} nonce Randomly generated 24byte nonce.
* @param {Buffer} salt Randomly generated 16byte salt.
* @param {Object=} options Encryption parameters.
* @param {String=} options.kdf Key derivation function (default: pbkdf2).
* @param {String=} options.cipher Symmetric cipher (default: constants.cipher).
* @param {Object=} options.kdfparams KDF parameters (default: constants.<kdf>).
* @return {Object}
*/
function _recover() {
_recover = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(password, keyObject) {
var nonce, salt, kdfParams, kdf, key;
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
validateKeyObj(keyObject);
nonce = Uint8Array.from(str2buf(keyObject.crypto.cipher_params.nonce));
salt = Uint8Array.from(str2buf(keyObject.crypto.kdf_params.salt));
kdfParams = keyObject.crypto.kdf_params;
kdf = keyObject.crypto.kdf;
_context4.t0 = decrypt;
_context4.t1 = Uint8Array.from(str2buf(keyObject.crypto.ciphertext));
_context4.next = 9;
return deriveKey(password, salt, {
kdf: kdf,
kdf_params: kdfParams
});
case 9:
_context4.t2 = _context4.sent;
_context4.t3 = nonce;
_context4.t4 = keyObject.crypto.symmetric_alg;
_context4.next = 14;
return (0, _context4.t0)(_context4.t1, _context4.t2, _context4.t3, _context4.t4);
case 14:
key = _context4.sent;
if (key) {
_context4.next = 17;
break;
}
throw new Error('Invalid password');
case 17:
if (!(Buffer.from(key).length === 64)) {
_context4.next = 19;
break;
}
return _context4.abrupt("return", Buffer.from(key).toString('hex'));
case 19:
return _context4.abrupt("return", Buffer.from(key).toString('utf-8'));
case 20:
case "end":
return _context4.stop();
}
}
}, _callee4);
}));
return _recover.apply(this, arguments);
}
export function dump(_x8, _x9, _x10) {
return _dump.apply(this, arguments);
}
function _dump() {
_dump = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(name, password, privateKey) {
var nonce,
salt,
options,
opt,
_args5 = arguments;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
nonce = _args5.length > 3 && _args5[3] !== undefined ? _args5[3] : nacl.randomBytes(24);
salt = _args5.length > 4 && _args5[4] !== undefined ? _args5[4] : nacl.randomBytes(16);
options = _args5.length > 5 && _args5[5] !== undefined ? _args5[5] : {};
opt = _Object$assign({}, DEFAULTS.crypto, options);
_context5.t0 = marshal;
_context5.t1 = name;
_context5.next = 8;
return deriveKey(password, salt, opt);
case 8:
_context5.t2 = _context5.sent;
_context5.t3 = privateKey;
_context5.t4 = nonce;
_context5.t5 = salt;
_context5.t6 = opt;
return _context5.abrupt("return", (0, _context5.t0)(_context5.t1, _context5.t2, _context5.t3, _context5.t4, _context5.t5, _context5.t6));
case 14:
case "end":
return _context5.stop();
}
}
}, _callee5);
}));
return _dump.apply(this, arguments);
}
export function validateKeyObj(obj) {
var root = ['crypto', 'id', 'version', 'public_key'];
var cryptoKeys = ['cipher_params', 'ciphertext', 'symmetric_alg', 'kdf', 'kdf_params'];
var missingRootKeys = _filterInstanceProperty(root).call(root, function (key) {
return !Object.prototype.hasOwnProperty.call(obj, key);
});
if (missingRootKeys.length) throw new Error("Invalid key file format. Require properties: ".concat(missingRootKeys));
var missingCryptoKeys = _filterInstanceProperty(cryptoKeys).call(cryptoKeys, function (key) {
return !Object.prototype.hasOwnProperty.call(obj.crypto, key);
});
if (missingCryptoKeys.length) throw new Error("Invalid key file format. Require properties: ".concat(missingCryptoKeys));
return true;
}
//# sourceMappingURL=keystore.js.map