From 6a9f3bc4d640c8df4fc23377e0a58655d1aaad69 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Wed, 13 Mar 2019 09:19:21 +0100 Subject: [PATCH 01/18] experimental version of eosjs-ecc that uses tweetnacl instead of aes-256-cbc --- package.json | 7 ++- src/aes.js | 125 +++++++++++++++++++++--------------------------- src/aes.test.js | 36 ++++++++++++++ 3 files changed, 93 insertions(+), 75 deletions(-) create mode 100644 src/aes.test.js diff --git a/package.json b/package.json index 95535c6..fadf371 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "eosjs-ecc", + "name": "eosjs-ecc-priveos", "version": "4.0.4", "description": "Elliptic curve cryptography functions", "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", @@ -30,13 +30,12 @@ }, "dependencies": { "bigi": "^1.4.2", - "browserify-aes": "^1.0.6", "bs58": "^4.0.1", - "bytebuffer": "^5.0.1", "create-hash": "^1.1.3", "create-hmac": "^1.1.6", "ecurve": "^1.0.5", - "randombytes": "^2.0.5" + "randombytes": "^2.0.5", + "tweetnacl": "^1.0.1" }, "license": "MIT", "devDependencies": { diff --git a/src/aes.js b/src/aes.js index 7e4307c..c067298 100644 --- a/src/aes.js +++ b/src/aes.js @@ -1,18 +1,17 @@ const randomBytes = require('randombytes') -const ByteBuffer = require('bytebuffer') -const crypto = require('browserify-aes') const assert = require('assert') const PublicKey = require('./key_public') const PrivateKey = require('./key_private') const hash = require('./hash') - -const Long = ByteBuffer.Long; +const nacl = require("tweetnacl/nacl-fast") module.exports = { encrypt, decrypt } +const nonceLength = 24 +const checkLength = 8 /** Spec: http://localhost:3002/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem @@ -20,15 +19,12 @@ module.exports = { @arg {PrivateKey} private_key - required and used for decryption @arg {PublicKey} public_key - required and used to calcualte the shared secret - @arg {string} [nonce = uniqueNonce()] - assigned a random unique uint64 @return {object} - @property {string} nonce - random or unique uint64, provides entropy when re-using the same private/public keys. - @property {Buffer} message - Plain text message - @property {number} checksum - shared secret checksum + @property {Buffer} message - Secret */ -function encrypt(private_key, public_key, message, nonce = uniqueNonce()) { - return crypt(private_key, public_key, nonce, message) +function encrypt(private_key, public_key, message) { + return crypt(private_key, public_key, message, true) } /** @@ -44,8 +40,8 @@ function encrypt(private_key, public_key, message, nonce = uniqueNonce()) { @return {Buffer} - message */ -function decrypt(private_key, public_key, nonce, message, checksum) { - return crypt(private_key, public_key, nonce, message, checksum).message +function decrypt(private_key, public_key, box) { + return crypt(private_key, public_key, box, false) } /** @@ -53,7 +49,8 @@ function decrypt(private_key, public_key, nonce, message, checksum) { @arg {number} checksum - shared secret checksum (null to encrypt, non-null to decrypt) @private */ -function crypt(private_key, public_key, nonce, message, checksum) { +function crypt(private_key, public_key, box, encrypt) { + let nonce, checksum, message private_key = PrivateKey(private_key) if (!private_key) throw new TypeError('private_key is required') @@ -62,7 +59,13 @@ function crypt(private_key, public_key, nonce, message, checksum) { if (!public_key) throw new TypeError('public_key is required') - nonce = toLongObj(nonce) + if(encrypt) { + nonce = uniqueNonce() + message = box + } else { + ({nonce, checksum, message} = deserialize(box)) + } + if (!nonce) throw new TypeError('nonce is required') @@ -71,96 +74,76 @@ function crypt(private_key, public_key, nonce, message, checksum) { throw new TypeError('message should be buffer or string') message = new Buffer(message, 'binary') } - if (checksum && typeof checksum !== 'number') - throw new TypeError('checksum should be a number') const S = private_key.getSharedSecret(public_key); - let ebuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN) - ebuf.writeUint64(nonce) - ebuf.append(S.toString('binary'), 'binary') - ebuf = new Buffer(ebuf.copy(0, ebuf.offset).toBinary(), 'binary') + const ekey_length = S.length + nonce.length + let ebuf = Buffer.concat([nonce, S], ekey_length) const encryption_key = hash.sha512(ebuf) - // D E B U G - // console.log('crypt', { - // priv_to_pub: private_key.toPublic().toString(), - // pub: public_key.toString(), - // nonce: nonce.toString(), - // message: message.length, - // checksum, - // S: S.toString('hex'), - // encryption_key: encryption_key.toString('hex'), - // }) - - const iv = encryption_key.slice(32, 48) + const iv = encryption_key.slice(32, 56) const key = encryption_key.slice(0, 32) - // check is first 64 bit of sha256 hash treated as uint64_t truncated to 32 bits. + // check is first 64 bit of sha256 hash let check = hash.sha256(encryption_key) - check = check.slice(0, 4) - const cbuf = ByteBuffer.fromBinary(check.toString('binary'), ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN) - check = cbuf.readUint32() + check = check.slice(0, 8) if (checksum) { - if (check !== checksum) - throw new Error('Invalid key') - message = cryptoJsDecrypt(message, key, iv) + if (!check.equals(checksum)) { + throw new Error('Invalid checksum') + } + return cryptoJsDecrypt(message, key, iv) } else { message = cryptoJsEncrypt(message, key, iv) + return serialize(nonce, check, message) } - return {nonce, message, checksum: check} } -/** This method does not use a checksum, the returned data must be validated some other way. +function serialize(nonce, check, message) { + const len = nonceLength + checkLength + message.length + return Buffer.concat([nonce, check, message], len) +} + +function deserialize(buf) { + const nonce = buf.slice(0, nonceLength) + const checksum = buf.slice(nonceLength, nonceLength + checkLength) + const message = buf.slice(nonceLength + checkLength) + return {nonce, checksum, message} +} +/** This method both decrypts and checks the authenticity of the messsage. @arg {string|Buffer} message - ciphertext binary format @arg {string|Buffer} key - 256bit - @arg {string|Buffer} iv - 128bit + @arg {string|Buffer} iv - 192bit @return {Buffer} */ -function cryptoJsDecrypt(message, key, iv) { - assert(message, "Missing cipher text") - message = toBinaryBuffer(message) - const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv) - // decipher.setAutoPadding(true) - message = Buffer.concat([decipher.update(message), decipher.final()]) - return message +function cryptoJsDecrypt(box, key, nonce) { + assert(box, "Missing cipher text") + box = toBinaryBuffer(box) + const decrypted = nacl.secretbox.open(box, nonce, key) + if(decrypted === null) { + throw new Error('Secretbox refused to open (most likely corrupted or tampered message)') + } + return Buffer.from(decrypted) } -/** This method does not use a checksum, the returned data must be validated some other way. +/** This method both encrypts and authenticates the message. @arg {string|Buffer} message - plaintext binary format @arg {string|Buffer} key - 256bit - @arg {string|Buffer} iv - 128bit + @arg {string|Buffer} iv - 192bit @return {Buffer} */ -function cryptoJsEncrypt(message, key, iv) { +function cryptoJsEncrypt(message, key, nonce) { assert(message, "Missing plain text") message = toBinaryBuffer(message) - const cipher = crypto.createCipheriv('aes-256-cbc', key, iv) - // cipher.setAutoPadding(true) - message = Buffer.concat([cipher.update(message), cipher.final()]) - return message + return nacl.secretbox(message, nonce, key) } -/** @return {string} unique 64 bit unsigned number string. Being time based, this is careful to never choose the same nonce twice. This value could be recorded in the blockchain for a long time. +/** @return {string} 192bit random nonce. Long enough to be unique. This value could be recorded in the blockchain for a long time. */ function uniqueNonce() { - if(unique_nonce_entropy === null) { - const b = new Uint8Array(randomBytes(2)) - unique_nonce_entropy = parseInt(b[0] << 8 | b[1], 10) - } - let long = Long.fromNumber(Date.now()) - const entropy = ++unique_nonce_entropy % 0xFFFF - // console.log('uniqueNonce date\t', ByteBuffer.allocate(8).writeUint64(long).toHex(0)) - // console.log('uniqueNonce entropy\t', ByteBuffer.allocate(8).writeUint64(Long.fromNumber(entropy)).toHex(0)) - long = long.shiftLeft(16).or(Long.fromNumber(entropy)); - // console.log('uniqueNonce final\t', ByteBuffer.allocate(8).writeUint64(long).toHex(0)) - return long.toString() + return randomBytes(nonceLength) } -let unique_nonce_entropy = null -// for(let i=1; i < 10; i++) key.uniqueNonce() -const toLongObj = o => (o ? Long.isLong(o) ? o : Long.fromString(o) : o) const toBinaryBuffer = o => (o ? Buffer.isBuffer(o) ? o : new Buffer(o, 'binary') : o) diff --git a/src/aes.test.js b/src/aes.test.js new file mode 100644 index 0000000..e4d825a --- /dev/null +++ b/src/aes.test.js @@ -0,0 +1,36 @@ +/* eslint-env mocha */ +const assert = require('assert') +const ecc = require('.') + +const alice = { + public_key: 'EOS81xEWcDyZCxACZcYQekiWXLjuSoPMwmRv16nZMuqm2BtQMvXbg', + private_key: '5JxhzyqYERz5MRSswNnDUXL1gFyM2m5Zxde9gGWfMkndbnjB8kD', +} +const bob = { + public_key: 'EOS7jAEWX9d4nZJWNckkaxBsHyqbe6yrVH6VUoCzP6DLxHAEvsBKM', + private_key: '5HrR1D5UbeeMETVR6Ud3Xc6PchVKbtAHmHiPmkmMQDqXY53bQKZ', +} + +describe('encrypt/decrypt', () => { + it('Decrypt should recover the original message', async function() { + const message = Buffer.from("My first message") + let box = ecc.Aes.encrypt(alice.private_key, bob.public_key, message) + const decrypted = ecc.Aes.decrypt(bob.private_key, alice.public_key, box) + assert.deepEqual(decrypted, message) + }) + + /* The following test fails with the normal eosjs-ecc */ + it('Tampered message should throw', async function() { + const message = Buffer.from("My first message") + let box = ecc.Aes.encrypt(alice.private_key, bob.public_key, message) + + // a little tampering + box = Buffer.concat([box, box]) + + assert.throws(function() { + ecc.Aes.decrypt(bob.private_key, alice.public_key, box) + }) + }) + +}) + From c4a6241eaa7a5943df3460d2a98af7e2794dc05a Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 25 Apr 2019 13:00:26 +0200 Subject: [PATCH 02/18] fix for browser --- src/aes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aes.js b/src/aes.js index c067298..26a9fcd 100644 --- a/src/aes.js +++ b/src/aes.js @@ -137,7 +137,7 @@ function cryptoJsDecrypt(box, key, nonce) { function cryptoJsEncrypt(message, key, nonce) { assert(message, "Missing plain text") message = toBinaryBuffer(message) - return nacl.secretbox(message, nonce, key) + return Buffer.from(nacl.secretbox(message, nonce, key)) } /** @return {string} 192bit random nonce. Long enough to be unique. This value could be recorded in the blockchain for a long time. From 145d9e66facaa3884d0375a893d422b0fc7fa04c Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 25 Apr 2019 13:01:17 +0200 Subject: [PATCH 03/18] ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c5272f8..3f0fc86 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ coverage test lib dist/*.js +.DS_Store From e609eeb16cd60da07d5a0f415830f415dd7d9376 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 25 Apr 2019 13:01:31 +0200 Subject: [PATCH 04/18] add package-lock --- package-lock.json | 109 +++++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 249b3ef..64da258 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "eosjs-ecc", + "name": "eosjs-ecc-priveos", "version": "4.0.4", "lockfileVersion": 1, "requires": true, @@ -216,6 +216,7 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -1540,6 +1541,15 @@ "optional": true, "requires": { "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + } } }, "bigi": { @@ -1703,6 +1713,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz", "integrity": "sha512-WYCMOT/PtGTlpOKFht0YJFYcPy6pLCR98CtWfzK13zoynLlBMvAdEMSRGmgnJCw2M2j/5qxBkinZQFobieM8dQ==", + "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -1817,7 +1828,8 @@ "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true }, "builtin-modules": { "version": "1.1.1", @@ -1831,14 +1843,6 @@ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, - "bytebuffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", - "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", - "requires": { - "long": "~3" - } - }, "bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", @@ -3243,6 +3247,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -3507,7 +3512,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3528,12 +3534,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3548,17 +3556,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3675,7 +3686,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3687,6 +3699,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3701,6 +3714,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3708,12 +3722,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3732,6 +3748,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3812,7 +3829,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3824,6 +3842,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3909,7 +3928,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3945,6 +3965,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3964,6 +3985,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4007,12 +4029,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -4113,6 +4137,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, + "optional": true, "requires": { "is-glob": "^2.0.0" } @@ -4730,7 +4755,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true + "dev": true, + "optional": true }, "is-finite": { "version": "1.0.2", @@ -4755,6 +4781,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -5230,16 +5257,12 @@ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, - "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" - }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "optional": true }, "longest-streak": { "version": "2.0.2", @@ -5304,6 +5327,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -5313,6 +5337,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -5737,6 +5762,7 @@ "version": "0.1.4", "bundled": true, "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -6058,7 +6084,8 @@ "is-buffer": { "version": "1.1.6", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "is-builtin-module": { "version": "1.0.0", @@ -6142,6 +6169,7 @@ "version": "3.2.2", "bundled": true, "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -6188,7 +6216,8 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "lru-cache": { "version": "4.1.3", @@ -6454,7 +6483,8 @@ "repeat-string": { "version": "1.6.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "require-directory": { "version": "2.1.1", @@ -8104,6 +8134,15 @@ "getpass": "^0.1.1", "jsbn": "~0.1.0", "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + } } }, "state-toggle": { @@ -8505,11 +8544,9 @@ } }, "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz", + "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==" }, "type-check": { "version": "0.3.2", From 86bdb9147a3fafb8844fce5188dd1dfc3c492766 Mon Sep 17 00:00:00 2001 From: fabifrank Date: Mon, 3 Jun 2019 08:59:08 +0200 Subject: [PATCH 05/18] installation instruction for eosjs-ecc-priveos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f305d4..a1c9015 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ Private Key, Public Key, Signature, AES, Encryption / Decryption # Import ```js -import ecc from 'eosjs-ecc' +import ecc from 'eosjs-ecc-priveos' // or -const ecc = require('eosjs-ecc') +const ecc = require('eosjs-ecc-priveos') ``` # Include From 7eb50faeec5c214dae211643256cef61270ff2de Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 25 Apr 2019 13:03:00 +0200 Subject: [PATCH 06/18] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fadf371..19a78a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eosjs-ecc-priveos", - "version": "4.0.4", + "version": "4.0.5", "description": "Elliptic curve cryptography functions", "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", "main": "lib/index.js", From f1e1cafff4b630b2b63b2914f315fe86a739200f Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Mon, 3 Jun 2019 21:31:30 +0200 Subject: [PATCH 07/18] no need to hash twice --- src/key_private.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/key_private.js b/src/key_private.js index 1ca8c71..450642f 100644 --- a/src/key_private.js +++ b/src/key_private.js @@ -76,7 +76,7 @@ function PrivateKey(d) { /** ECIES @arg {string|Object} pubkey wif, PublicKey object - @return {Buffer} 64 byte shared secret + @return {Buffer} 32 byte shared secret */ function getSharedSecret(public_key) { public_key = PublicKey(public_key) @@ -89,8 +89,7 @@ function PrivateKey(d) { let r = toBuffer() let P = KBP.multiply(BigInteger.fromBuffer(r)) let S = P.affineX.toBuffer({size: 32}) - // SHA512 used in ECIES - return hash.sha512(S) + return S } // /** ECIES TODO unit test From 9ffac4bd318c4a161eca8332c0a8818e9276656d Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Mon, 3 Jun 2019 21:31:49 +0200 Subject: [PATCH 08/18] add support for encryption with pre-existing shared secret --- src/aes.js | 89 ++++++++++++++++++++++++++++--------------------- src/aes.test.js | 8 +++++ 2 files changed, 59 insertions(+), 38 deletions(-) diff --git a/src/aes.js b/src/aes.js index 26a9fcd..c007b64 100644 --- a/src/aes.js +++ b/src/aes.js @@ -7,7 +7,9 @@ const nacl = require("tweetnacl/nacl-fast") module.exports = { encrypt, - decrypt + decrypt, + decrypt_shared_secret, + encrypt_shared_secret, } const nonceLength = 24 @@ -27,6 +29,9 @@ function encrypt(private_key, public_key, message) { return crypt(private_key, public_key, message, true) } +function encrypt_shared_secret(shared_secret, message) { + return crypt_shared_secret(shared_secret, message, true) +} /** Spec: http://localhost:3002/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem @@ -44,6 +49,10 @@ function decrypt(private_key, public_key, box) { return crypt(private_key, public_key, box, false) } +function decrypt_shared_secret(shared_secret, box) { + return crypt_shared_secret(shared_secret, box, false) +} + /** @arg {Buffer} message - Encrypted or plain text message (see checksum) @arg {number} checksum - shared secret checksum (null to encrypt, non-null to decrypt) @@ -57,45 +66,49 @@ function crypt(private_key, public_key, box, encrypt) { public_key = PublicKey(public_key) if (!public_key) - throw new TypeError('public_key is required') + throw new TypeError('public_key is required') - if(encrypt) { - nonce = uniqueNonce() - message = box - } else { - ({nonce, checksum, message} = deserialize(box)) - } + const S = private_key.getSharedSecret(public_key); + return crypt_shared_secret(S, box, encrypt); - if (!nonce) - throw new TypeError('nonce is required') - - if (!Buffer.isBuffer(message)) { - if (typeof message !== 'string') - throw new TypeError('message should be buffer or string') - message = new Buffer(message, 'binary') - } +} - const S = private_key.getSharedSecret(public_key); - const ekey_length = S.length + nonce.length - let ebuf = Buffer.concat([nonce, S], ekey_length) - const encryption_key = hash.sha512(ebuf) - - const iv = encryption_key.slice(32, 56) - const key = encryption_key.slice(0, 32) - - // check is first 64 bit of sha256 hash - let check = hash.sha256(encryption_key) - check = check.slice(0, 8) - - if (checksum) { - if (!check.equals(checksum)) { - throw new Error('Invalid checksum') - } - return cryptoJsDecrypt(message, key, iv) - } else { - message = cryptoJsEncrypt(message, key, iv) - return serialize(nonce, check, message) - } +function crypt_shared_secret(S, box, encrypt) { + let nonce, checksum, message + if(encrypt) { + nonce = uniqueNonce() + message = box + } else { + ({nonce, checksum, message} = deserialize(box)) + } + if (!Buffer.isBuffer(message)) { + if (typeof message !== 'string') + throw new TypeError('message should be buffer or string') + message = new Buffer(message, 'binary') + } + assert(Buffer.isBuffer(S), "S is not a buffer") + assert(Buffer.isBuffer(nonce), "nonce is not a buffer") + + const ekey_length = S.length + nonce.length + let ebuf = Buffer.concat([nonce, S], ekey_length) + const encryption_key = hash.sha512(ebuf) + + const iv = encryption_key.slice(32, 56) + const key = encryption_key.slice(0, 32) + + // check is first 64 bit of sha256 hash + let check = hash.sha256(encryption_key) + check = check.slice(0, 8) + + if (checksum) { + if (!check.equals(checksum)) { + throw new Error('Invalid checksum') + } + return cryptoJsDecrypt(message, key, iv) + } else { + message = cryptoJsEncrypt(message, key, iv) + return serialize(nonce, check, message) + } } function serialize(nonce, check, message) { @@ -122,7 +135,7 @@ function cryptoJsDecrypt(box, key, nonce) { box = toBinaryBuffer(box) const decrypted = nacl.secretbox.open(box, nonce, key) if(decrypted === null) { - throw new Error('Secretbox refused to open (most likely corrupted or tampered message)') + throw new Error('Secretbox refused to open (wrong key or corrupted or tampered message)') } return Buffer.from(decrypted) } diff --git a/src/aes.test.js b/src/aes.test.js index e4d825a..9e0828a 100644 --- a/src/aes.test.js +++ b/src/aes.test.js @@ -32,5 +32,13 @@ describe('encrypt/decrypt', () => { }) }) + it("encryption with pre-existing shared secret", async function() { + const shared_secret = Buffer.from("1234") + const message = Buffer.from("My first message") + const box = ecc.Aes.encrypt_shared_secret(shared_secret, message) + const decrypted =ecc.Aes.decrypt_shared_secret(shared_secret, box) + assert.deepEqual(decrypted, message) + }) + }) From dc8918e7e5db752b8bede4fceeb74e56043796f0 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 13 Jun 2019 11:33:54 +0200 Subject: [PATCH 09/18] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19a78a3..a146937 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eosjs-ecc-priveos", - "version": "4.0.5", + "version": "4.0.6", "description": "Elliptic curve cryptography functions", "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", "main": "lib/index.js", From f838ddc5e3b74d78228aaaf128df9bf3cd9b0965 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 13 Jun 2019 12:31:37 +0200 Subject: [PATCH 10/18] use terser instead of uglifyjs to support es6 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a146937..66584c4 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build_browser": "mkdir -p lib && browserify -o lib/eosjs-ecc.js -s eosjs_ecc lib/index.js", "build_browser_test": "npm run build && browserify -o dist/test.js lib/*.test.js", "documentation": "node_modules/documentation/bin/documentation.js", - "minimize": "uglifyjs lib/eosjs-ecc.js -o lib/eosjs-ecc.min.js --source-map --compress --mangle", + "minimize": "terser lib/eosjs-ecc.js -o lib/eosjs-ecc.min.js --source-map --compress --mangle", "docs": "npm run documentation -- readme src/api_common.js --section \"Common API\" --shallow", "srisum": "npx srisum lib/eosjs-ecc.*", "prepublishOnly": "npm run build && npm run test_lib && npm run minimize && npm run docs && npm run srisum" @@ -35,6 +35,7 @@ "create-hmac": "^1.1.6", "ecurve": "^1.0.5", "randombytes": "^2.0.5", + "terser": "^4.0.0", "tweetnacl": "^1.0.1" }, "license": "MIT", @@ -47,8 +48,7 @@ "documentation": "^8.1.1", "istanbul": "^0.4.5", "mocha": "^5.2.0", - "nyc": "^13.0.1", - "uglify-js": "3.4.2" + "nyc": "^13.0.1" }, "babel": { "presets": [ From 5a120f9ce0e9040a974def15d0591100da502dd0 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Sat, 15 Jun 2019 17:15:53 +0200 Subject: [PATCH 11/18] =?UTF-8?q?disable=20slow=20entropy=20collection=20(?= =?UTF-8?q?it=E2=80=99s=20pointless=20on=20modern=20browsers)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common.test.js | 13 ------------- src/key_private.js | 6 +++--- src/key_utils.js | 3 --- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/common.test.js b/src/common.test.js index 04778a3..0636260 100644 --- a/src/common.test.js +++ b/src/common.test.js @@ -81,16 +81,3 @@ describe('Common API', () => { }) }) -describe('Common API (initialized)', () => { - it('initialize', () => ecc.initialize()) - - it('randomKey', () => { - const cpuEntropyBits = 1 - ecc.key_utils.addEntropy(1, 2, 3) - const pvt = ecc.unsafeRandomKey().then(pvt => { - assert.equal(typeof pvt, 'string', 'pvt') - assert(/^5[HJK]/.test(wif)) - // assert(/^PVT_K1_/.test(pvt)) - }) - }) -}) diff --git a/src/key_private.js b/src/key_private.js index 450642f..5938bd3 100644 --- a/src/key_private.js +++ b/src/key_private.js @@ -267,9 +267,9 @@ function initialize() { return } - unitTest() - keyUtils.addEntropy(...keyUtils.cpuEntropy()) - assert(keyUtils.entropyCount() >= 128, 'insufficient entropy') + // unitTest() + // keyUtils.addEntropy(...keyUtils.cpuEntropy()) + // assert(keyUtils.entropyCount() >= 128, 'insufficient entropy') initialized = true } diff --git a/src/key_utils.js b/src/key_utils.js index 6c4d121..5697ead 100644 --- a/src/key_utils.js +++ b/src/key_utils.js @@ -33,9 +33,6 @@ function random32ByteBuffer({cpuEntropyBits = 0, safe = true} = {}) { assert.equal(typeof cpuEntropyBits, 'number', 'cpuEntropyBits') assert.equal(typeof safe, 'boolean', 'boolean') - if(safe) { - assert(entropyCount >= 128, 'Call initialize() to add entropy') - } // if(entropyCount > 0) { // console.log(`Additional private key entropy: ${entropyCount} events`) From f1dbc5fbff8a2398dc90963c6dbe32c021037887 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Sat, 15 Jun 2019 17:18:02 +0200 Subject: [PATCH 12/18] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66584c4..d64f3ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eosjs-ecc-priveos", - "version": "4.0.6", + "version": "4.0.7", "description": "Elliptic curve cryptography functions", "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", "main": "lib/index.js", From 75bc6d484a9be7269fcb22d85e3c21a2ba725962 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 18 Jul 2019 13:24:31 +0200 Subject: [PATCH 13/18] =?UTF-8?q?don=E2=80=99t=20unnecessarily=20leak=20a?= =?UTF-8?q?=20hash=20of=20the=20shared=20secret?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aes.js | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/aes.js b/src/aes.js index c007b64..d9ce143 100644 --- a/src/aes.js +++ b/src/aes.js @@ -13,7 +13,6 @@ module.exports = { } const nonceLength = 24 -const checkLength = 8 /** Spec: http://localhost:3002/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem @@ -59,7 +58,7 @@ function decrypt_shared_secret(shared_secret, box) { @private */ function crypt(private_key, public_key, box, encrypt) { - let nonce, checksum, message + let nonce, message private_key = PrivateKey(private_key) if (!private_key) throw new TypeError('private_key is required') @@ -74,12 +73,12 @@ function crypt(private_key, public_key, box, encrypt) { } function crypt_shared_secret(S, box, encrypt) { - let nonce, checksum, message + let nonce, message if(encrypt) { nonce = uniqueNonce() message = box } else { - ({nonce, checksum, message} = deserialize(box)) + ({nonce, message} = deserialize(box)) } if (!Buffer.isBuffer(message)) { if (typeof message !== 'string') @@ -96,31 +95,23 @@ function crypt_shared_secret(S, box, encrypt) { const iv = encryption_key.slice(32, 56) const key = encryption_key.slice(0, 32) - // check is first 64 bit of sha256 hash - let check = hash.sha256(encryption_key) - check = check.slice(0, 8) - - if (checksum) { - if (!check.equals(checksum)) { - throw new Error('Invalid checksum') - } - return cryptoJsDecrypt(message, key, iv) - } else { + if (encrypt) { message = cryptoJsEncrypt(message, key, iv) - return serialize(nonce, check, message) + return serialize(nonce, message) + } else { + return cryptoJsDecrypt(message, key, iv) } } -function serialize(nonce, check, message) { - const len = nonceLength + checkLength + message.length - return Buffer.concat([nonce, check, message], len) +function serialize(nonce, message) { + const len = nonceLength + message.length + return Buffer.concat([nonce, message], len) } function deserialize(buf) { const nonce = buf.slice(0, nonceLength) - const checksum = buf.slice(nonceLength, nonceLength + checkLength) - const message = buf.slice(nonceLength + checkLength) - return {nonce, checksum, message} + const message = buf.slice(nonceLength) + return {nonce, message} } /** This method both decrypts and checks the authenticity of the messsage. From ac446b91567772c353ea065729e1c040d46dc6fc Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Thu, 18 Jul 2019 13:25:19 +0200 Subject: [PATCH 14/18] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d64f3ab..6cf42ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eosjs-ecc-priveos", - "version": "4.0.7", + "version": "4.0.8", "description": "Elliptic curve cryptography functions", "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", "main": "lib/index.js", From fbeb396d842b98fdd1dfaafee0a9f20300df94d3 Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Tue, 23 Jul 2019 11:00:15 +0200 Subject: [PATCH 15/18] remove references to eosjs-ecc-priveos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea5453f..8965621 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ Private Key, Public Key, Signature, AES, Encryption / Decryption # Import ```js -import ecc from 'eosjs-ecc-priveos' +import ecc from 'eosjs-ecc' // or -const ecc = require('eosjs-ecc-priveos') +const ecc = require('eosjs-ecc') ``` # Include From 078e2d9e9965fa44c47b05570beb9c74aa20878d Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Tue, 23 Jul 2019 11:00:22 +0200 Subject: [PATCH 16/18] rename & version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6cf42ea..d797c74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "eosjs-ecc-priveos", - "version": "4.0.8", + "name": "eosjs-ecc", + "version": "4.0.7", "description": "Elliptic curve cryptography functions", "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", "main": "lib/index.js", From 81c068476c6147223efbb8a7f2a84a028a7ba5ed Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Tue, 23 Jul 2019 11:09:07 +0200 Subject: [PATCH 17/18] use upstream package.json --- package.json | 70 +++++++++++++++++++++++++++++++++------------------- yarn.lock | 9 +++++-- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index d797c74..419fccc 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,16 @@ { "name": "eosjs-ecc", - "version": "4.0.7", + "version": "4.0.6", "description": "Elliptic curve cryptography functions", - "keywords": "ECC, Private Key, Public Key, Signature, AES, Encryption, Decryption", + "keywords": [ + "ECC", + "Private Key", + "Public Key", + "Signature", + "AES", + "Encryption", + "Decryption" + ], "main": "lib/index.js", "files": [ "README.md", @@ -12,47 +20,57 @@ "scripts": { "test": "mocha --use_strict src/*.test.js", "test_lib": "mocha --use_strict lib/*.test.js", - "coverage": "nyc --reporter=html npm test", - "coveralls": "npm run coverage && cat ./coverage/lcov.info | ./node_modules/.bin/coveralls", - "build": "npm run build_lib && npm run build_browser", + "coverage": "nyc --reporter=lcov --reporter=text npm test", + "coveralls": "yarn coverage && cat ./coverage/lcov.info | ./node_modules/.bin/coveralls", + "build": "yarn build_lib && yarn build_browser", "build_lib": "rm -f lib/* && babel src --out-dir lib", "build_browser": "mkdir -p lib && browserify -o lib/eosjs-ecc.js -s eosjs_ecc lib/index.js", - "build_browser_test": "npm run build && browserify -o dist/test.js lib/*.test.js", + "build_browser_test": "yarn build && browserify -o dist/test.js lib/*.test.js", "documentation": "node_modules/documentation/bin/documentation.js", "minimize": "terser lib/eosjs-ecc.js -o lib/eosjs-ecc.min.js --source-map --compress --mangle", - "docs": "npm run documentation -- readme src/api_common.js --section \"Common API\" --shallow", + "docs": "yarn documentation -- readme src/api_common.js --section \"Common API\" --shallow", "srisum": "npx srisum lib/eosjs-ecc.*", - "prepublishOnly": "npm run build && npm run test_lib && npm run minimize && npm run docs && npm run srisum" + "prepublishOnly": "yarn build && yarn minimize && yarn test_lib && yarn docs && yarn srisum" }, "repository": { "type": "git", "url": "git://github.com/EOSIO/eosjs-ecc.git" }, "dependencies": { - "bigi": "^1.4.2", - "bs58": "^4.0.1", - "create-hash": "^1.1.3", - "create-hmac": "^1.1.6", - "ecurve": "^1.0.5", - "randombytes": "^2.0.5", - "terser": "^4.0.0", - "tweetnacl": "^1.0.1" + "@babel/runtime": "7.4.4", + "bigi": "1.4.2", + "browserify-aes": "1.0.6", + "bs58": "4.0.1", + "bytebuffer": "5.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ecurve": "1.0.5", + "randombytes": "2.0.5", + "tweetnacl": "1.0.1" }, "license": "MIT", "devDependencies": { - "babel-cli": "6.26.0", - "babel-core": "^6.26.3", - "babel-preset-es2015": "6.24.1", - "browserify": "14.4.0", - "coveralls": "^3.0.0", - "documentation": "^8.1.1", - "istanbul": "^0.4.5", - "mocha": "^5.2.0", - "nyc": "^13.0.1" + "@babel/cli": "7.4.4", + "@babel/core": "7.4.4", + "@babel/plugin-transform-runtime": "7.4.4", + "@babel/preset-env": "7.4.4", + "browserify": "16.2.3", + "coveralls": "3.0.3", + "documentation": "8.1.1", + "istanbul": "0.4.5", + "mocha": "5.2.0", + "nyc": "14.1.0", + "terser": "3.17.0" + }, + "nyc": { + "temp-directory": "./coverage/.nyc_output" }, "babel": { "presets": [ - "es2015" + "@babel/preset-env" + ], + "plugins": [ + "@babel/plugin-transform-runtime" ] } } diff --git a/yarn.lock b/yarn.lock index 37124ea..02ffe40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -502,7 +502,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-runtime@^7.4.4": +"@babel/plugin-transform-runtime@7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.4.tgz#a50f5d16e9c3a4ac18a1a9f9803c107c380bce08" integrity sha512-aMVojEjPszvau3NRg+TIH14ynZLvPewH4xhlCW1w6A3rkxTS1m4uwzRclYR9oS+rl/dr+kT+pzbfHuAWP/lc7Q== @@ -612,7 +612,7 @@ js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/runtime@^7.4.4": +"@babel/runtime@7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d" integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg== @@ -6295,6 +6295,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tweetnacl@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17" + integrity sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A== + tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" From 8d9611412b012734b82d61a49b93f52d2022f33b Mon Sep 17 00:00:00 2001 From: Angelo Laub Date: Tue, 23 Jul 2019 14:42:48 +0200 Subject: [PATCH 18/18] cleanup dependencies --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 419fccc..a99debc 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,7 @@ "dependencies": { "@babel/runtime": "7.4.4", "bigi": "1.4.2", - "browserify-aes": "1.0.6", "bs58": "4.0.1", - "bytebuffer": "5.0.1", "create-hash": "1.1.3", "create-hmac": "1.1.6", "ecurve": "1.0.5",