@hiveio/dhive 1.2.4 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dhive.d.ts +69 -5
- package/dist/dhive.js +1 -1
- package/dist/dhive.js.gz +0 -0
- package/dist/dhive.js.map +1 -1
- package/lib/chain/deserializer.d.ts +6 -0
- package/lib/chain/deserializer.js +51 -0
- package/lib/chain/serializer.d.ts +5 -2
- package/lib/chain/serializer.js +9 -35
- package/lib/client.d.ts +1 -1
- package/lib/crypto.d.ts +13 -2
- package/lib/crypto.js +31 -0
- package/lib/helpers/aes.d.ts +26 -0
- package/lib/helpers/aes.js +116 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +2 -0
- package/lib/memo.d.ts +20 -0
- package/lib/memo.js +72 -0
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +4 -5
- package/lib/version.js +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ByteBuffer = require("bytebuffer");
|
|
4
|
+
const crypto_1 = require("../crypto");
|
|
5
|
+
const PublicKeyDeserializer = (buf) => {
|
|
6
|
+
const c = fixed_buf(buf, 33);
|
|
7
|
+
return crypto_1.PublicKey.fromBuffer(c);
|
|
8
|
+
};
|
|
9
|
+
const UInt64Deserializer = (b) => b.readUint64();
|
|
10
|
+
const UInt32Deserializer = (b) => b.readUint32();
|
|
11
|
+
const BinaryDeserializer = (b) => {
|
|
12
|
+
const len = b.readVarint32();
|
|
13
|
+
const b_copy = b.copy(b.offset, b.offset + len);
|
|
14
|
+
b.skip(len);
|
|
15
|
+
return Buffer.from(b_copy.toBinary(), 'binary');
|
|
16
|
+
};
|
|
17
|
+
const BufferDeserializer = (keyDeserializers) => (buf) => {
|
|
18
|
+
const obj = {};
|
|
19
|
+
for (const [key, deserializer] of keyDeserializers) {
|
|
20
|
+
try {
|
|
21
|
+
// Decodes a binary encoded string to a ByteBuffer.
|
|
22
|
+
buf = ByteBuffer.fromBinary(buf.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
|
|
23
|
+
obj[key] = deserializer(buf);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
error.message = `${key}: ${error.message}`;
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return obj;
|
|
31
|
+
};
|
|
32
|
+
function fixed_buf(b, len) {
|
|
33
|
+
if (!b) {
|
|
34
|
+
throw Error('No buffer found on first parameter');
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const b_copy = b.copy(b.offset, b.offset + len);
|
|
38
|
+
b.skip(len);
|
|
39
|
+
return Buffer.from(b_copy.toBinary(), 'binary');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const EncryptedMemoDeserializer = BufferDeserializer([
|
|
43
|
+
['from', PublicKeyDeserializer],
|
|
44
|
+
['to', PublicKeyDeserializer],
|
|
45
|
+
['nonce', UInt64Deserializer],
|
|
46
|
+
['check', UInt32Deserializer],
|
|
47
|
+
['encrypted', BinaryDeserializer]
|
|
48
|
+
]);
|
|
49
|
+
exports.types = {
|
|
50
|
+
EncryptedMemoD: EncryptedMemoDeserializer
|
|
51
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
/**
|
|
2
3
|
* @file Hive protocol serialization.
|
|
3
4
|
* @author Johan Nordberg <code@johan-nordberg.com>
|
|
@@ -32,7 +33,6 @@
|
|
|
32
33
|
* You acknowledge that this software is not designed, licensed or intended for use
|
|
33
34
|
* in the design, construction, operation or maintenance of any military facility.
|
|
34
35
|
*/
|
|
35
|
-
/// <reference types="node" />
|
|
36
36
|
import * as ByteBuffer from 'bytebuffer';
|
|
37
37
|
import { PublicKey } from '../crypto';
|
|
38
38
|
import { Asset } from './asset';
|
|
@@ -48,6 +48,9 @@ export declare const Types: {
|
|
|
48
48
|
Binary: (size?: number | undefined) => (buffer: ByteBuffer, data: Buffer | HexBuffer) => void;
|
|
49
49
|
Boolean: (buffer: ByteBuffer, data: boolean) => void;
|
|
50
50
|
Date: (buffer: ByteBuffer, data: string) => void;
|
|
51
|
+
EncryptedMemo: (buffer: ByteBuffer, data: {
|
|
52
|
+
[key: string]: any;
|
|
53
|
+
}) => void;
|
|
51
54
|
FlatMap: (keySerializer: Serializer, valueSerializer: Serializer) => (buffer: ByteBuffer, data: [any, any][]) => void;
|
|
52
55
|
Int16: (buffer: ByteBuffer, data: number) => void;
|
|
53
56
|
Int32: (buffer: ByteBuffer, data: number) => void;
|
|
@@ -71,5 +74,5 @@ export declare const Types: {
|
|
|
71
74
|
UInt32: (buffer: ByteBuffer, data: number) => void;
|
|
72
75
|
UInt64: (buffer: ByteBuffer, data: number) => void;
|
|
73
76
|
UInt8: (buffer: ByteBuffer, data: number) => void;
|
|
74
|
-
Void: (
|
|
77
|
+
Void: () => never;
|
|
75
78
|
};
|
package/lib/chain/serializer.js
CHANGED
|
@@ -1,43 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @file Hive protocol serialization.
|
|
4
|
-
* @author Johan Nordberg <code@johan-nordberg.com>
|
|
5
|
-
* @license
|
|
6
|
-
* Copyright (c) 2017 Johan Nordberg. All Rights Reserved.
|
|
7
|
-
*
|
|
8
|
-
* Redistribution and use in source and binary forms, with or without modification,
|
|
9
|
-
* are permitted provided that the following conditions are met:
|
|
10
|
-
*
|
|
11
|
-
* 1. Redistribution of source code must retain the above copyright notice, this
|
|
12
|
-
* list of conditions and the following disclaimer.
|
|
13
|
-
*
|
|
14
|
-
* 2. Redistribution in binary form must reproduce the above copyright notice,
|
|
15
|
-
* this list of conditions and the following disclaimer in the documentation
|
|
16
|
-
* and/or other materials provided with the distribution.
|
|
17
|
-
*
|
|
18
|
-
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
19
|
-
* may be used to endorse or promote products derived from this software without
|
|
20
|
-
* specific prior written permission.
|
|
21
|
-
*
|
|
22
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
23
|
-
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
24
|
-
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
25
|
-
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
26
|
-
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
27
|
-
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
28
|
-
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
29
|
-
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
30
|
-
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
31
|
-
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
-
*
|
|
33
|
-
* You acknowledge that this software is not designed, licensed or intended for use
|
|
34
|
-
* in the design, construction, operation or maintenance of any military facility.
|
|
35
|
-
*/
|
|
36
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
3
|
const crypto_1 = require("../crypto");
|
|
38
4
|
const asset_1 = require("./asset");
|
|
39
5
|
const misc_1 = require("./misc");
|
|
40
|
-
const VoidSerializer = (
|
|
6
|
+
const VoidSerializer = () => {
|
|
41
7
|
throw new Error('Void can not be serialized');
|
|
42
8
|
};
|
|
43
9
|
const StringSerializer = (buffer, data) => {
|
|
@@ -178,6 +144,13 @@ const ChainPropertiesSerializer = ObjectSerializer([
|
|
|
178
144
|
['maximum_block_size', UInt32Serializer],
|
|
179
145
|
['hbd_interest_rate', UInt16Serializer]
|
|
180
146
|
]);
|
|
147
|
+
const EncryptedMemoSerializer = ObjectSerializer([
|
|
148
|
+
['from', PublicKeySerializer],
|
|
149
|
+
['to', PublicKeySerializer],
|
|
150
|
+
['nonce', UInt64Serializer],
|
|
151
|
+
['check', UInt32Serializer],
|
|
152
|
+
['encrypted', BinarySerializer()]
|
|
153
|
+
]);
|
|
181
154
|
const OperationDataSerializer = (operationId, definitions) => {
|
|
182
155
|
const objectSerializer = ObjectSerializer(definitions);
|
|
183
156
|
return (buffer, data) => {
|
|
@@ -537,6 +510,7 @@ exports.Types = {
|
|
|
537
510
|
Binary: BinarySerializer,
|
|
538
511
|
Boolean: BooleanSerializer,
|
|
539
512
|
Date: DateSerializer,
|
|
513
|
+
EncryptedMemo: EncryptedMemoSerializer,
|
|
540
514
|
FlatMap: FlatMapSerializer,
|
|
541
515
|
Int16: Int16Serializer,
|
|
542
516
|
Int32: Int32Serializer,
|
package/lib/client.d.ts
CHANGED
|
@@ -154,11 +154,11 @@ export declare class Client {
|
|
|
154
154
|
* Address prefix for current network.
|
|
155
155
|
*/
|
|
156
156
|
readonly addressPrefix: string;
|
|
157
|
+
currentAddress: string;
|
|
157
158
|
private timeout;
|
|
158
159
|
private backoff;
|
|
159
160
|
private failoverThreshold;
|
|
160
161
|
private consoleOnFailover;
|
|
161
|
-
currentAddress: string;
|
|
162
162
|
/**
|
|
163
163
|
* @param address The address to the Hive RPC server,
|
|
164
164
|
* e.g. `https://api.hive.blog`. or [`https://api.hive.blog`, `https://another.api.com`]
|
package/lib/crypto.d.ts
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
* in the design, construction, operation or maintenance of any military facility.
|
|
34
34
|
*/
|
|
35
35
|
/// <reference types="node" />
|
|
36
|
+
import * as ByteBuffer from 'bytebuffer';
|
|
36
37
|
import { SignedTransaction, Transaction } from './chain/transaction';
|
|
37
38
|
/**
|
|
38
39
|
* Network id used in WIF-encoding.
|
|
@@ -74,9 +75,13 @@ declare function isWif(privWif: string | Buffer): boolean;
|
|
|
74
75
|
* ECDSA (secp256k1) public key.
|
|
75
76
|
*/
|
|
76
77
|
export declare class PublicKey {
|
|
77
|
-
readonly key:
|
|
78
|
+
readonly key: any;
|
|
78
79
|
readonly prefix: string;
|
|
79
|
-
|
|
80
|
+
readonly uncompressed: Buffer;
|
|
81
|
+
constructor(key: any, prefix?: string);
|
|
82
|
+
static fromBuffer(key: ByteBuffer): {
|
|
83
|
+
key: ByteBuffer;
|
|
84
|
+
};
|
|
80
85
|
/**
|
|
81
86
|
* Create a new instance from a WIF-encoded key.
|
|
82
87
|
*/
|
|
@@ -110,6 +115,7 @@ export declare type KeyRole = 'owner' | 'active' | 'posting' | 'memo';
|
|
|
110
115
|
*/
|
|
111
116
|
export declare class PrivateKey {
|
|
112
117
|
private key;
|
|
118
|
+
secret: Buffer;
|
|
113
119
|
constructor(key: Buffer);
|
|
114
120
|
/**
|
|
115
121
|
* Convenience to create a new instance from WIF string or buffer.
|
|
@@ -127,6 +133,7 @@ export declare class PrivateKey {
|
|
|
127
133
|
* Create key from username and password.
|
|
128
134
|
*/
|
|
129
135
|
static fromLogin(username: string, password: string, role?: KeyRole): PrivateKey;
|
|
136
|
+
multiply(pub: any): Buffer;
|
|
130
137
|
/**
|
|
131
138
|
* Sign message.
|
|
132
139
|
* @param message 32-byte message.
|
|
@@ -145,6 +152,10 @@ export declare class PrivateKey {
|
|
|
145
152
|
* to get the full encoded key you need to explicitly call {@link toString}.
|
|
146
153
|
*/
|
|
147
154
|
inspect(): string;
|
|
155
|
+
/**
|
|
156
|
+
* Get shared secret for memo cryptography
|
|
157
|
+
*/
|
|
158
|
+
get_shared_secret(public_key: PublicKey): Buffer;
|
|
148
159
|
}
|
|
149
160
|
/**
|
|
150
161
|
* ECDSA (secp256k1) signature.
|
package/lib/crypto.js
CHANGED
|
@@ -35,15 +35,21 @@
|
|
|
35
35
|
*/
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
const assert = require("assert");
|
|
38
|
+
const bigInteger = require("bigi");
|
|
38
39
|
const bs58 = require("bs58");
|
|
39
40
|
const ByteBuffer = require("bytebuffer");
|
|
40
41
|
const crypto_1 = require("crypto");
|
|
42
|
+
const ecurve = require("ecurve");
|
|
41
43
|
const Ripemd160 = require("ripemd160");
|
|
42
44
|
const secp256k1 = require("secp256k1");
|
|
43
45
|
const verror_1 = require("verror");
|
|
44
46
|
const serializer_1 = require("./chain/serializer");
|
|
45
47
|
const client_1 = require("./client");
|
|
46
48
|
const utils_1 = require("./utils");
|
|
49
|
+
/**
|
|
50
|
+
* secp256k1 ecurve
|
|
51
|
+
*/
|
|
52
|
+
const secp256k1Curve = ecurve.getCurveByName('secp256k1');
|
|
47
53
|
/**
|
|
48
54
|
* Network id used in WIF-encoding.
|
|
49
55
|
*/
|
|
@@ -64,6 +70,14 @@ function sha256(input) {
|
|
|
64
70
|
.update(input)
|
|
65
71
|
.digest();
|
|
66
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Return sha512 hash of input
|
|
75
|
+
*/
|
|
76
|
+
function sha512(input) {
|
|
77
|
+
return crypto_1.createHash('sha512')
|
|
78
|
+
.update(input)
|
|
79
|
+
.digest();
|
|
80
|
+
}
|
|
67
81
|
/**
|
|
68
82
|
* Return 2-round sha256 hash of input.
|
|
69
83
|
*/
|
|
@@ -145,6 +159,11 @@ class PublicKey {
|
|
|
145
159
|
this.key = key;
|
|
146
160
|
this.prefix = prefix;
|
|
147
161
|
assert(secp256k1.publicKeyVerify(key), 'invalid public key');
|
|
162
|
+
this.uncompressed = Buffer.from(secp256k1.publicKeyConvert(key, false));
|
|
163
|
+
}
|
|
164
|
+
static fromBuffer(key) {
|
|
165
|
+
assert(secp256k1.publicKeyVerify(key), 'invalid buffer as public key');
|
|
166
|
+
return { key };
|
|
148
167
|
}
|
|
149
168
|
/**
|
|
150
169
|
* Create a new instance from a WIF-encoded key.
|
|
@@ -230,6 +249,9 @@ class PrivateKey {
|
|
|
230
249
|
const seed = username + role + password;
|
|
231
250
|
return PrivateKey.fromSeed(seed);
|
|
232
251
|
}
|
|
252
|
+
multiply(pub) {
|
|
253
|
+
return Buffer.from(secp256k1.publicKeyTweakMul(pub.key, this.secret, false));
|
|
254
|
+
}
|
|
233
255
|
/**
|
|
234
256
|
* Sign message.
|
|
235
257
|
* @param message 32-byte message.
|
|
@@ -265,6 +287,15 @@ class PrivateKey {
|
|
|
265
287
|
const key = this.toString();
|
|
266
288
|
return `PrivateKey: ${key.slice(0, 6)}...${key.slice(-6)}`;
|
|
267
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Get shared secret for memo cryptography
|
|
292
|
+
*/
|
|
293
|
+
get_shared_secret(public_key) {
|
|
294
|
+
const KBP = ecurve.Point.fromAffine(secp256k1Curve, bigInteger.fromBuffer(public_key.uncompressed.slice(1, 33)), bigInteger.fromBuffer(public_key.uncompressed.slice(33, 65)));
|
|
295
|
+
const P = KBP.multiply(bigInteger.fromBuffer(this.key));
|
|
296
|
+
const S = P.affineX.toBuffer({ size: 32 });
|
|
297
|
+
return sha512(S);
|
|
298
|
+
}
|
|
268
299
|
}
|
|
269
300
|
exports.PrivateKey = PrivateKey;
|
|
270
301
|
/**
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PrivateKey, PublicKey } from '../crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Spec: http://peakd.com/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem
|
|
4
|
+
* @throws {Error|TypeError} - "Invalid Key, ..."
|
|
5
|
+
* @param {PrivateKey} private_key - required and used for decryption
|
|
6
|
+
* @param {PublicKey} public_key - required and used to calcualte the shared secret
|
|
7
|
+
* @param message - message to be encrypted
|
|
8
|
+
* @param {string} [nonce = uniqueNonce()] - assigned a random unique uint64
|
|
9
|
+
*
|
|
10
|
+
* @return {object}
|
|
11
|
+
* @property {string} nonce - random or unique uint64, provides entropy when re-using the same private/public keys.
|
|
12
|
+
* @property {Buffer} message - Plain text message
|
|
13
|
+
* @property {number} checksum - shared secret checksum
|
|
14
|
+
*/
|
|
15
|
+
export declare function encrypt(private_key: PrivateKey, public_key: PublicKey, message: any, nonce: any): any;
|
|
16
|
+
/**
|
|
17
|
+
* Spec: http://peakd.com/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem
|
|
18
|
+
* @arg {PrivateKey} private_key - required and used for decryption
|
|
19
|
+
* @arg {PublicKey} public_key - required and used to calcualte the shared secret
|
|
20
|
+
* @arg {string} nonce - random or unique uint64, provides entropy when re-using the same private/public keys.
|
|
21
|
+
* @arg {Buffer} message - Encrypted or plain text message
|
|
22
|
+
* @arg {number} checksum - shared secret checksum
|
|
23
|
+
* @throws {Error|TypeError} - "Invalid Key, ..."
|
|
24
|
+
* @return {Buffer} - message
|
|
25
|
+
*/
|
|
26
|
+
export declare function decrypt(private_key: PrivateKey, public_key: PublicKey, nonce: any, message: any, checksum: number): string;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const assert = require("assert");
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const ByteBuffer = require('bytebuffer');
|
|
6
|
+
const Long = ByteBuffer.Long;
|
|
7
|
+
/**
|
|
8
|
+
* Spec: http://peakd.com/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem
|
|
9
|
+
* @throws {Error|TypeError} - "Invalid Key, ..."
|
|
10
|
+
* @param {PrivateKey} private_key - required and used for decryption
|
|
11
|
+
* @param {PublicKey} public_key - required and used to calcualte the shared secret
|
|
12
|
+
* @param message - message to be encrypted
|
|
13
|
+
* @param {string} [nonce = uniqueNonce()] - assigned a random unique uint64
|
|
14
|
+
*
|
|
15
|
+
* @return {object}
|
|
16
|
+
* @property {string} nonce - random or unique uint64, provides entropy when re-using the same private/public keys.
|
|
17
|
+
* @property {Buffer} message - Plain text message
|
|
18
|
+
* @property {number} checksum - shared secret checksum
|
|
19
|
+
*/
|
|
20
|
+
function encrypt(private_key, public_key, message, nonce) {
|
|
21
|
+
// Change message to varint32 prefixed encoded string
|
|
22
|
+
const mbuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
|
|
23
|
+
mbuf.writeVString(message);
|
|
24
|
+
message = Buffer.from(mbuf.flip().toBinary());
|
|
25
|
+
return crypt(private_key, public_key, uniqueNonce(), message);
|
|
26
|
+
}
|
|
27
|
+
exports.encrypt = encrypt;
|
|
28
|
+
/**
|
|
29
|
+
* Spec: http://peakd.com/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem
|
|
30
|
+
* @arg {PrivateKey} private_key - required and used for decryption
|
|
31
|
+
* @arg {PublicKey} public_key - required and used to calcualte the shared secret
|
|
32
|
+
* @arg {string} nonce - random or unique uint64, provides entropy when re-using the same private/public keys.
|
|
33
|
+
* @arg {Buffer} message - Encrypted or plain text message
|
|
34
|
+
* @arg {number} checksum - shared secret checksum
|
|
35
|
+
* @throws {Error|TypeError} - "Invalid Key, ..."
|
|
36
|
+
* @return {Buffer} - message
|
|
37
|
+
*/
|
|
38
|
+
function decrypt(private_key, public_key, nonce, message, checksum) {
|
|
39
|
+
return crypt(private_key, public_key, nonce, message, checksum).message;
|
|
40
|
+
}
|
|
41
|
+
exports.decrypt = decrypt;
|
|
42
|
+
/**
|
|
43
|
+
* @arg {Buffer} message - Encrypted or plain text message (see checksum)
|
|
44
|
+
* @arg {number} checksum - shared secret checksum (null to encrypt, non-null to decrypt)
|
|
45
|
+
*/
|
|
46
|
+
function crypt(private_key, public_key, nonce, message, checksum) {
|
|
47
|
+
nonce = toLongObj(nonce);
|
|
48
|
+
// Appending nonce to buffer "ebuf" and rehash with sha512
|
|
49
|
+
const S = private_key.get_shared_secret(public_key);
|
|
50
|
+
let ebuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
|
|
51
|
+
ebuf.writeUint64(nonce);
|
|
52
|
+
ebuf.append(S.toString('binary'), 'binary');
|
|
53
|
+
ebuf = Buffer.from(ebuf.copy(0, ebuf.offset).toBinary(), 'binary');
|
|
54
|
+
const encryption_key = crypto_1.createHash('sha512').update(ebuf).digest();
|
|
55
|
+
const iv = encryption_key.slice(32, 48);
|
|
56
|
+
const tag = encryption_key.slice(0, 32);
|
|
57
|
+
// check if first 64 bit of sha256 hash treated as uint64_t truncated to 32 bits.
|
|
58
|
+
let check = crypto_1.createHash('sha256').update(encryption_key).digest();
|
|
59
|
+
check = check.slice(0, 4);
|
|
60
|
+
const cbuf = ByteBuffer.fromBinary(check.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
|
|
61
|
+
check = cbuf.readUint32();
|
|
62
|
+
if (checksum) {
|
|
63
|
+
if (check !== checksum) {
|
|
64
|
+
throw new Error('Invalid nonce');
|
|
65
|
+
}
|
|
66
|
+
message = cryptoJsDecrypt(message, tag, iv);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
message = cryptoJsEncrypt(message, tag, iv);
|
|
70
|
+
}
|
|
71
|
+
return { nonce, message, checksum: check };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* This method does not use a checksum, the returned data must be validated some other way.
|
|
75
|
+
* @arg {string|Buffer} ciphertext - binary format
|
|
76
|
+
* @return {Buffer} the decrypted message
|
|
77
|
+
*/
|
|
78
|
+
function cryptoJsDecrypt(message, tag, iv) {
|
|
79
|
+
assert(message, 'Missing cipher text');
|
|
80
|
+
message = toBinaryBuffer(message);
|
|
81
|
+
const decipher = crypto_1.createDecipheriv('aes-256-cbc', tag, iv);
|
|
82
|
+
message = Buffer.concat([decipher.update(message), decipher.final()]);
|
|
83
|
+
return message;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* This method does not use a checksum, the returned data must be validated some other way.
|
|
87
|
+
* @arg {string|Buffer} plaintext - binary format
|
|
88
|
+
* @return {Buffer} binary
|
|
89
|
+
*/
|
|
90
|
+
function cryptoJsEncrypt(message, tag, iv) {
|
|
91
|
+
assert(message, 'Missing plain text');
|
|
92
|
+
message = toBinaryBuffer(message);
|
|
93
|
+
const cipher = crypto_1.createCipheriv('aes-256-cbc', tag, iv);
|
|
94
|
+
message = Buffer.concat([cipher.update(message), cipher.final()]);
|
|
95
|
+
return message;
|
|
96
|
+
}
|
|
97
|
+
/** @return {string} unique 64 bit unsigned number string. Being time based,
|
|
98
|
+
* this is careful to never choose the same nonce twice. This value could
|
|
99
|
+
* clsbe recorded in the blockchain for a long time.
|
|
100
|
+
*/
|
|
101
|
+
let unique_nonce_entropy = null;
|
|
102
|
+
function uniqueNonce() {
|
|
103
|
+
if (unique_nonce_entropy === null) {
|
|
104
|
+
const uint8randomArr = new Uint8Array(2);
|
|
105
|
+
for (let i = 0; i < 2; ++i) {
|
|
106
|
+
uint8randomArr[i] = crypto_1.randomBytes(2).readUInt8(i);
|
|
107
|
+
}
|
|
108
|
+
unique_nonce_entropy = uint8randomArr[0] << 8 | uint8randomArr[1];
|
|
109
|
+
}
|
|
110
|
+
let long = Long.fromNumber(Date.now());
|
|
111
|
+
const entropy = ++unique_nonce_entropy % 0xFFFF;
|
|
112
|
+
long = long.shiftLeft(16).or(Long.fromNumber(entropy));
|
|
113
|
+
return long.toString();
|
|
114
|
+
}
|
|
115
|
+
const toLongObj = o => (o ? Long.isLong(o) ? o : Long.fromString(o) : o);
|
|
116
|
+
const toBinaryBuffer = o => (o ? Buffer.isBuffer(o) ? o : Buffer.from(o, 'binary') : o);
|
package/lib/index.d.ts
CHANGED
|
@@ -46,6 +46,9 @@ export * from './chain/comment';
|
|
|
46
46
|
export * from './chain/misc';
|
|
47
47
|
export * from './chain/operation';
|
|
48
48
|
export * from './chain/serializer';
|
|
49
|
+
export * from './chain/deserializer';
|
|
49
50
|
export * from './chain/transaction';
|
|
51
|
+
export * from './chain/hivemind';
|
|
50
52
|
export * from './client';
|
|
51
53
|
export * from './crypto';
|
|
54
|
+
export * from './memo';
|
package/lib/index.js
CHANGED
|
@@ -48,5 +48,7 @@ __export(require("./chain/account"));
|
|
|
48
48
|
__export(require("./chain/asset"));
|
|
49
49
|
__export(require("./chain/misc"));
|
|
50
50
|
__export(require("./chain/serializer"));
|
|
51
|
+
__export(require("./chain/deserializer"));
|
|
51
52
|
__export(require("./client"));
|
|
52
53
|
__export(require("./crypto"));
|
|
54
|
+
__export(require("./memo"));
|
package/lib/memo.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PrivateKey, PublicKey } from './crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Memo/Any message encoding using AES (aes-cbc algorithm)
|
|
4
|
+
* @param {Buffer|String} private_key Privatekey of sender
|
|
5
|
+
* @param {Buffer|String}public_key publickey of recipient
|
|
6
|
+
* @param {String}memo message to be encrypted
|
|
7
|
+
* @param {Number}testNonce nonce with high entropy
|
|
8
|
+
*/
|
|
9
|
+
declare function encode(private_key: PrivateKey | string, public_key: PublicKey | string, memo: string, testNonce?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Encrypted memo/message decryption
|
|
12
|
+
* @param {Buffer|string}private_key Privatekey of recipient
|
|
13
|
+
* @param {any}memo Encrypted message/memo
|
|
14
|
+
*/
|
|
15
|
+
declare function decode(private_key: PrivateKey | string, memo: any): any;
|
|
16
|
+
export declare const Memo: {
|
|
17
|
+
decode: typeof decode;
|
|
18
|
+
encode: typeof encode;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
package/lib/memo.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const bs58 = require("bs58");
|
|
4
|
+
const ByteBuffer = require("bytebuffer");
|
|
5
|
+
const deserializer_1 = require("./chain/deserializer");
|
|
6
|
+
const serializer_1 = require("./chain/serializer");
|
|
7
|
+
const crypto_1 = require("./crypto");
|
|
8
|
+
const Aes = require("./helpers/aes");
|
|
9
|
+
/**
|
|
10
|
+
* Memo/Any message encoding using AES (aes-cbc algorithm)
|
|
11
|
+
* @param {Buffer|String} private_key Privatekey of sender
|
|
12
|
+
* @param {Buffer|String}public_key publickey of recipient
|
|
13
|
+
* @param {String}memo message to be encrypted
|
|
14
|
+
* @param {Number}testNonce nonce with high entropy
|
|
15
|
+
*/
|
|
16
|
+
function encode(private_key, public_key, memo, testNonce) {
|
|
17
|
+
if (!memo.startsWith('#')) {
|
|
18
|
+
return memo;
|
|
19
|
+
}
|
|
20
|
+
memo = memo.substring(1);
|
|
21
|
+
private_key = toPrivateObj(private_key);
|
|
22
|
+
public_key = toPublicObj(public_key);
|
|
23
|
+
const { nonce, message, checksum } = Aes.encrypt(private_key, public_key, memo, testNonce);
|
|
24
|
+
const mbuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
|
|
25
|
+
serializer_1.Types.EncryptedMemo(mbuf, {
|
|
26
|
+
check: checksum,
|
|
27
|
+
encrypted: message,
|
|
28
|
+
from: private_key.createPublic(),
|
|
29
|
+
nonce,
|
|
30
|
+
to: public_key
|
|
31
|
+
});
|
|
32
|
+
mbuf.flip();
|
|
33
|
+
const data = Buffer.from(mbuf.toBuffer());
|
|
34
|
+
return '#' + bs58.encode(data);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Encrypted memo/message decryption
|
|
38
|
+
* @param {Buffer|string}private_key Privatekey of recipient
|
|
39
|
+
* @param {any}memo Encrypted message/memo
|
|
40
|
+
*/
|
|
41
|
+
function decode(private_key, memo) {
|
|
42
|
+
if (!memo.startsWith('#')) {
|
|
43
|
+
return memo;
|
|
44
|
+
}
|
|
45
|
+
memo = memo.substring(1);
|
|
46
|
+
// checkEncryption()
|
|
47
|
+
private_key = toPrivateObj(private_key);
|
|
48
|
+
memo = bs58.decode(memo);
|
|
49
|
+
memo = deserializer_1.types.EncryptedMemoD(Buffer.from(memo, 'binary'));
|
|
50
|
+
const { from, to, nonce, check, encrypted } = memo;
|
|
51
|
+
const pubkey = private_key.createPublic().toString();
|
|
52
|
+
const otherpub = pubkey === new crypto_1.PublicKey(from.key).toString() ? new crypto_1.PublicKey(to.key) : new crypto_1.PublicKey(from.key);
|
|
53
|
+
memo = Aes.decrypt(private_key, otherpub, nonce, encrypted, check);
|
|
54
|
+
// remove varint length prefix
|
|
55
|
+
const mbuf = ByteBuffer.fromBinary(memo.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
|
|
56
|
+
try {
|
|
57
|
+
mbuf.mark();
|
|
58
|
+
return '#' + mbuf.readVString();
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
mbuf.reset();
|
|
62
|
+
// Sender did not length-prefix the memo
|
|
63
|
+
memo = Buffer.from(mbuf.toString('binary'), 'binary').toString('utf-8');
|
|
64
|
+
return '#' + memo;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const toPrivateObj = (o) => (o ? o.key ? o : crypto_1.PrivateKey.fromString(o) : o /* null or undefined*/);
|
|
68
|
+
const toPublicObj = (o) => (o ? o.key ? o : crypto_1.PublicKey.fromString(o) : o /* null or undefined*/);
|
|
69
|
+
exports.Memo = {
|
|
70
|
+
decode,
|
|
71
|
+
encode
|
|
72
|
+
};
|
package/lib/utils.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ export interface WitnessProps {
|
|
|
71
71
|
hbd_interest_rate?: number;
|
|
72
72
|
url?: string;
|
|
73
73
|
}
|
|
74
|
-
export declare
|
|
74
|
+
export declare const buildWitnessUpdateOp: (owner: string, props: WitnessProps) => WitnessSetPropertiesOperation;
|
|
75
75
|
export declare const operationOrders: {
|
|
76
76
|
vote: number;
|
|
77
77
|
comment: number;
|
package/lib/utils.js
CHANGED
|
@@ -182,15 +182,15 @@ const failover = (url, urls, currentAddress, consoleOnFailover) => {
|
|
|
182
182
|
// Can hopefully be removed when hived's JSON representation is fixed
|
|
183
183
|
const ByteBuffer = require("bytebuffer");
|
|
184
184
|
const serializer_1 = require("./chain/serializer");
|
|
185
|
-
|
|
185
|
+
const serialize = (serializer, data) => {
|
|
186
186
|
const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
|
|
187
187
|
serializer(buffer, data);
|
|
188
188
|
buffer.flip();
|
|
189
189
|
// `props` values must be hex
|
|
190
190
|
return buffer.toString('hex');
|
|
191
191
|
// return Buffer.from(buffer.toBuffer());
|
|
192
|
-
}
|
|
193
|
-
|
|
192
|
+
};
|
|
193
|
+
exports.buildWitnessUpdateOp = (owner, props) => {
|
|
194
194
|
const data = {
|
|
195
195
|
extensions: [],
|
|
196
196
|
owner,
|
|
@@ -227,8 +227,7 @@ function buildWitnessUpdateOp(owner, props) {
|
|
|
227
227
|
}
|
|
228
228
|
data.props.sort((a, b) => a[0].localeCompare(b[0]));
|
|
229
229
|
return ['witness_set_properties', data];
|
|
230
|
-
}
|
|
231
|
-
exports.buildWitnessUpdateOp = buildWitnessUpdateOp;
|
|
230
|
+
};
|
|
232
231
|
const JSBI = require('jsbi');
|
|
233
232
|
exports.operationOrders = {
|
|
234
233
|
vote: 0,
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hiveio/dhive",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Hive blockchain RPC client library",
|
|
5
5
|
"author": "hive-network",
|
|
6
6
|
"license": "BSD-3-Clause-No-Military-License",
|
|
@@ -32,10 +32,12 @@
|
|
|
32
32
|
"dhive"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"bigi": "^1.4.2",
|
|
35
36
|
"bs58": "^4.0.1",
|
|
36
37
|
"bytebuffer": "^5.0.1",
|
|
37
38
|
"core-js": "^3.6.4",
|
|
38
39
|
"cross-fetch": "^3.0.4",
|
|
40
|
+
"ecurve": "^1.0.6",
|
|
39
41
|
"https": "^1.0.0",
|
|
40
42
|
"jsbi": "^3.1.4",
|
|
41
43
|
"node-fetch": "^2.6.0",
|