@vex-chat/crypto 0.7.19 → 0.8.0
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/README.md +8 -5
- package/RELEASING.md +85 -0
- package/dist/index.d.ts +6 -7
- package/dist/index.js +116 -90
- package/jest.config.js +14 -11
- package/mise.toml +3 -0
- package/package.json +60 -60
- package/dist/__tests__/XKeyConvert.d.ts +0 -1
- package/dist/__tests__/XKeyConvert.js +0 -51
- package/dist/__tests__/XUtils/bytesEqual.d.ts +0 -1
- package/dist/__tests__/XUtils/bytesEqual.js +0 -13
- package/dist/__tests__/XUtils/emptyHeader.d.ts +0 -1
- package/dist/__tests__/XUtils/emptyHeader.js +0 -10
- package/dist/__tests__/XUtils/keyFileFunctions.d.ts +0 -1
- package/dist/__tests__/XUtils/keyFileFunctions.js +0 -18
- package/dist/__tests__/XUtils/numberToUint8Arr.d.ts +0 -1
- package/dist/__tests__/XUtils/numberToUint8Arr.js +0 -29
- package/dist/__tests__/XUtils/packMessage.d.ts +0 -1
- package/dist/__tests__/XUtils/packMessage.js +0 -16
- package/dist/__tests__/XUtils/stringEncoding.d.ts +0 -1
- package/dist/__tests__/XUtils/stringEncoding.js +0 -57
- package/dist/__tests__/XUtils/uint8ArrToNumber.d.ts +0 -1
- package/dist/__tests__/XUtils/uint8ArrToNumber.js +0 -28
- package/dist/__tests__/XUtils/unpackMessage.d.ts +0 -1
- package/dist/__tests__/XUtils/unpackMessage.js +0 -24
- package/dist/__tests__/xConcat.d.ts +0 -1
- package/dist/__tests__/xConcat.js +0 -11
- package/dist/__tests__/xDH.d.ts +0 -1
- package/dist/__tests__/xDH.js +0 -10
- package/dist/__tests__/xEncode.d.ts +0 -1
- package/dist/__tests__/xEncode.js +0 -9
- package/dist/__tests__/xHMAC.d.ts +0 -1
- package/dist/__tests__/xHMAC.js +0 -12
- package/dist/__tests__/xMnemonic.d.ts +0 -1
- package/dist/__tests__/xMnemonic.js +0 -9
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changesets
|
|
2
|
+
|
|
3
|
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
+
find the full documentation for it [in the changesets repo](https://github.com/changesets/changesets)
|
|
6
|
+
|
|
7
|
+
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json",
|
|
3
|
+
"changelog": "@changesets/cli/changelog",
|
|
4
|
+
"commit": false,
|
|
5
|
+
"fixed": [],
|
|
6
|
+
"linked": [],
|
|
7
|
+
"access": "public",
|
|
8
|
+
"baseBranch": "master",
|
|
9
|
+
"updateInternalDependencies": "patch",
|
|
10
|
+
"ignore": []
|
|
11
|
+
}
|
package/README.md
CHANGED
|
@@ -8,8 +8,11 @@ All of the crypto functions for the key exchange are contained in here.
|
|
|
8
8
|
|
|
9
9
|
## external crypto dependencies
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
11
|
+
This library utilizes native Node.js crypto where possible for performance and security.
|
|
12
|
+
|
|
13
|
+
- **tweetnacl**: Primitives for signing and encryption (X25519 / Ed25519).
|
|
14
|
+
- **ed2curve**: Ed25519 signing key to X25519 encryption key conversion.
|
|
15
|
+
- **msgpackr**: High-performance MessagePack serialization (replacing `msgpack-lite`).
|
|
16
|
+
- **bip39**: Mnemonic generation for keys.
|
|
17
|
+
- **Node Crypto**: Native implementations for HKDF, PBKDF2, HMAC, and SHA hashing (replacing `futoin-hkdf`, `create-hmac`, and `sha.js`).
|
|
18
|
+
- **@stablelib**: Constant-time encoding for Base64 and UTF8.
|
package/RELEASING.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Releasing @vex-chat/crypto
|
|
2
|
+
|
|
3
|
+
This repo uses [Changesets](https://github.com/changesets/changesets) for versioning and publishing.
|
|
4
|
+
|
|
5
|
+
## Dependency Chain
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@vex-chat/types
|
|
9
|
+
└─ @vex-chat/crypto ← you are here
|
|
10
|
+
└─ @vex-chat/libvex
|
|
11
|
+
└─ vex-desktop
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Publish types first** if it has changes, then publish crypto.
|
|
15
|
+
|
|
16
|
+
## Day-to-Day Workflow
|
|
17
|
+
|
|
18
|
+
### 1. Work on a feature branch
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git checkout -b my-feature
|
|
22
|
+
# ... make changes ...
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Add a changeset before pushing
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx changeset
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This prompts you to:
|
|
32
|
+
- Select the package (`@vex-chat/crypto`)
|
|
33
|
+
- Choose bump type (patch / minor / major)
|
|
34
|
+
- Write a short summary of the change
|
|
35
|
+
|
|
36
|
+
It creates a file in `.changeset/` — commit it with your code.
|
|
37
|
+
|
|
38
|
+
### 3. Push and open a PR
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git add .
|
|
42
|
+
git commit -m "my feature"
|
|
43
|
+
git push -u origin my-feature
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 4. Merge to master
|
|
47
|
+
|
|
48
|
+
After merge, the **Release** GitHub Action will:
|
|
49
|
+
1. Detect pending changesets
|
|
50
|
+
2. Open a **"chore: version packages"** PR with bumped version + updated CHANGELOG.md
|
|
51
|
+
3. When you merge that PR, it publishes to npm automatically
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Release Candidates
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx changeset pre enter rc # enter RC mode
|
|
59
|
+
npx changeset version # produces e.g. 0.9.0-rc.0
|
|
60
|
+
npx changeset publish # publishes with --tag rc
|
|
61
|
+
|
|
62
|
+
# ... more changes + changesets ...
|
|
63
|
+
npx changeset version # produces 0.9.0-rc.1
|
|
64
|
+
npx changeset publish
|
|
65
|
+
|
|
66
|
+
# ready for stable:
|
|
67
|
+
npx changeset pre exit
|
|
68
|
+
npx changeset version # produces 0.9.0
|
|
69
|
+
npx changeset publish # publishes as @latest
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## GitHub Secrets Required
|
|
73
|
+
|
|
74
|
+
- `NPM_TOKEN` — npm access token with publish permission for `@vex-chat` scope
|
|
75
|
+
- `GITHUB_TOKEN` — provided automatically by GitHub Actions
|
|
76
|
+
|
|
77
|
+
## Local Development
|
|
78
|
+
|
|
79
|
+
You can still use `yalc` for local cross-repo development:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
yarn push # builds and pushes to yalc for local consumers
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
When publishing for real, changesets handles versioning — yalc is just for local dev loops.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import { decode as decodeBase64, encode as encodeBase64 } from "@stablelib/base64";
|
|
3
2
|
import { decode as encodeUTF8, encode as decodeUTF8 } from "@stablelib/utf8";
|
|
4
|
-
import {
|
|
3
|
+
import { IBaseMsg } from "@vex-chat/types";
|
|
5
4
|
import ed2curve from "ed2curve";
|
|
6
5
|
/**
|
|
7
6
|
* Provides an interface that can map an ed25519 keypair to its equivalent
|
|
@@ -49,20 +48,20 @@ export declare class XUtils {
|
|
|
49
48
|
* @param arr The array to convert.
|
|
50
49
|
* @returns [32 byte header, message body]
|
|
51
50
|
*/
|
|
52
|
-
static unpackMessage(msg: Uint8Array | Buffer): [Uint8Array,
|
|
51
|
+
static unpackMessage(msg: Uint8Array | Buffer): [Uint8Array, IBaseMsg];
|
|
53
52
|
/**
|
|
54
53
|
* Packs a javascript object and a 32 byte header into a vex message.
|
|
55
54
|
*
|
|
56
55
|
* @param arr The array to convert.
|
|
57
56
|
* @returns the packed message.
|
|
58
57
|
*/
|
|
59
|
-
static packMessage(msg: any, header?: Uint8Array): Uint8Array
|
|
58
|
+
static packMessage(msg: any, header?: Uint8Array): Uint8Array<ArrayBufferLike>;
|
|
60
59
|
/**
|
|
61
60
|
* Returns the empty header (32 0's)
|
|
62
61
|
*
|
|
63
62
|
* @returns The empty header.
|
|
64
63
|
*/
|
|
65
|
-
static emptyHeader(): Uint8Array
|
|
64
|
+
static emptyHeader(): Uint8Array<ArrayBuffer>;
|
|
66
65
|
/**
|
|
67
66
|
* Encrypts a secret key with a password and saves it as a file.
|
|
68
67
|
*
|
|
@@ -72,7 +71,7 @@ export declare class XUtils {
|
|
|
72
71
|
* @param iterationOverride An optional override if you'd prefer to manually
|
|
73
72
|
* select your iterations rather than having a random amount selected.
|
|
74
73
|
*/
|
|
75
|
-
static saveKeyFile: (path: string, password: string, keyToSave: string, iterationOverride?: number
|
|
74
|
+
static saveKeyFile: (path: string, password: string, keyToSave: string, iterationOverride?: number) => void;
|
|
76
75
|
/**
|
|
77
76
|
* Decrypts and returns a secret key stored in a file with saveKeyFile().
|
|
78
77
|
*
|
|
@@ -106,7 +105,7 @@ export declare function xMnemonic(entropy: Uint8Array, wordList?: string[] | und
|
|
|
106
105
|
* @param msg the message to create the HMAC of
|
|
107
106
|
* @param SK the secret key to create the HMAC with
|
|
108
107
|
*/
|
|
109
|
-
export declare function xHMAC(msg: any, SK: Uint8Array): Uint8Array
|
|
108
|
+
export declare function xHMAC(msg: any, SK: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
110
109
|
/**
|
|
111
110
|
* Constants for vex.
|
|
112
111
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -11,29 +15,49 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
11
15
|
}) : function(o, v) {
|
|
12
16
|
o["default"] = v;
|
|
13
17
|
});
|
|
14
|
-
var __importStar = (this && this.__importStar) || function (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
21
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
37
|
};
|
|
24
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
39
|
+
exports.xConstants = exports.XUtils = exports.XKeyConvert = void 0;
|
|
40
|
+
exports.xMnemonic = xMnemonic;
|
|
41
|
+
exports.xHMAC = xHMAC;
|
|
42
|
+
exports.xMakeNonce = xMakeNonce;
|
|
43
|
+
exports.xKDF = xKDF;
|
|
44
|
+
exports.xHash = xHash;
|
|
45
|
+
exports.xDH = xDH;
|
|
46
|
+
exports.xConcat = xConcat;
|
|
47
|
+
exports.xEncode = xEncode;
|
|
26
48
|
const base64_1 = require("@stablelib/base64");
|
|
27
49
|
const utf8_1 = require("@stablelib/utf8");
|
|
28
50
|
const bip39 = __importStar(require("bip39"));
|
|
29
|
-
const
|
|
51
|
+
const node_crypto_1 = require("node:crypto");
|
|
30
52
|
const ed2curve_1 = __importDefault(require("ed2curve"));
|
|
31
53
|
const fs_1 = __importDefault(require("fs"));
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const pbkdf2_1 = require("pbkdf2");
|
|
54
|
+
const node_crypto_2 = require("node:crypto");
|
|
55
|
+
const msgpackr_1 = require("msgpackr");
|
|
35
56
|
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
36
|
-
const
|
|
57
|
+
const packer = new msgpackr_1.Packr({
|
|
58
|
+
useRecords: false,
|
|
59
|
+
moreTypes: true,
|
|
60
|
+
});
|
|
37
61
|
/**
|
|
38
62
|
* Provides an interface that can map an ed25519 keypair to its equivalent
|
|
39
63
|
* X25519 keypair.
|
|
@@ -44,6 +68,10 @@ exports.XKeyConvert = ed2curve_1.default;
|
|
|
44
68
|
* vex messages.
|
|
45
69
|
*/
|
|
46
70
|
class XUtils {
|
|
71
|
+
static encodeUTF8 = utf8_1.decode;
|
|
72
|
+
static decodeUTF8 = utf8_1.encode;
|
|
73
|
+
static encodeBase64 = base64_1.encode;
|
|
74
|
+
static decodeBase64 = base64_1.decode;
|
|
47
75
|
/**
|
|
48
76
|
* Checks if two buffer-like objects are equal.
|
|
49
77
|
*
|
|
@@ -102,7 +130,8 @@ class XUtils {
|
|
|
102
130
|
static unpackMessage(msg) {
|
|
103
131
|
const msgp = Uint8Array.from(msg);
|
|
104
132
|
const msgh = msgp.slice(0, exports.xConstants.HEADER_SIZE);
|
|
105
|
-
|
|
133
|
+
// UPDATED: Use msgpackr
|
|
134
|
+
const msgb = packer.unpack(msgp.slice(exports.xConstants.HEADER_SIZE));
|
|
106
135
|
return [msgh, msgb];
|
|
107
136
|
}
|
|
108
137
|
/**
|
|
@@ -112,7 +141,8 @@ class XUtils {
|
|
|
112
141
|
* @returns the packed message.
|
|
113
142
|
*/
|
|
114
143
|
static packMessage(msg, header) {
|
|
115
|
-
|
|
144
|
+
// UPDATED: Use msgpackr
|
|
145
|
+
const msgb = packer.pack(msg);
|
|
116
146
|
const msgh = header || XUtils.emptyHeader();
|
|
117
147
|
return xConcat(msgh, msgb);
|
|
118
148
|
}
|
|
@@ -124,6 +154,63 @@ class XUtils {
|
|
|
124
154
|
static emptyHeader() {
|
|
125
155
|
return new Uint8Array(exports.xConstants.HEADER_SIZE);
|
|
126
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Encrypts a secret key with a password and saves it as a file.
|
|
159
|
+
*
|
|
160
|
+
* @param path The path to save the keyfile.
|
|
161
|
+
* @param password The password to encrypt the keyfile with.
|
|
162
|
+
* @param keyToSave The key to encrypt.
|
|
163
|
+
* @param iterationOverride An optional override if you'd prefer to manually
|
|
164
|
+
* select your iterations rather than having a random amount selected.
|
|
165
|
+
*/
|
|
166
|
+
static saveKeyFile = (path, password, keyToSave, iterationOverride) => {
|
|
167
|
+
const UNENCRYPTED_SIGNKEY = XUtils.decodeHex(keyToSave);
|
|
168
|
+
const OFFSET = 1000;
|
|
169
|
+
// generate random amount of iterations using Native Crypto
|
|
170
|
+
const rand = (0, node_crypto_1.randomBytes)(2);
|
|
171
|
+
const N1 = rand[0];
|
|
172
|
+
const N2 = rand[1];
|
|
173
|
+
const iterations = iterationOverride ? iterationOverride : N1 * N2 + OFFSET;
|
|
174
|
+
const ITERATIONS = XUtils.numberToUint8Arr(iterations);
|
|
175
|
+
const PKBDF_SALT = xMakeNonce();
|
|
176
|
+
const ENCRYPTION_KEY = (0, node_crypto_1.pbkdf2Sync)(password, PKBDF_SALT, iterations, 32, "sha512");
|
|
177
|
+
const NONCE = xMakeNonce();
|
|
178
|
+
const ENCRYPTED_SIGNKEY = tweetnacl_1.default.secretbox(UNENCRYPTED_SIGNKEY, NONCE, new Uint8Array(ENCRYPTION_KEY));
|
|
179
|
+
const result = new Uint8Array(ITERATIONS.length +
|
|
180
|
+
PKBDF_SALT.length +
|
|
181
|
+
NONCE.length +
|
|
182
|
+
ENCRYPTED_SIGNKEY.length);
|
|
183
|
+
let offset = 0;
|
|
184
|
+
result.set(ITERATIONS, offset);
|
|
185
|
+
offset += ITERATIONS.length;
|
|
186
|
+
result.set(PKBDF_SALT, offset);
|
|
187
|
+
offset += PKBDF_SALT.length;
|
|
188
|
+
result.set(NONCE, offset);
|
|
189
|
+
offset += NONCE.length;
|
|
190
|
+
result.set(ENCRYPTED_SIGNKEY, offset);
|
|
191
|
+
fs_1.default.writeFileSync(path, result);
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Decrypts and returns a secret key stored in a file with saveKeyFile().
|
|
195
|
+
*
|
|
196
|
+
* @param path The path of the file.
|
|
197
|
+
* @param password The password the file was encrypted with.
|
|
198
|
+
*/
|
|
199
|
+
static loadKeyFile = (path, password) => {
|
|
200
|
+
const keyFile = Uint8Array.from(fs_1.default.readFileSync(path));
|
|
201
|
+
const ITERATIONS = XUtils.uint8ArrToNumber(keyFile.slice(0, 6));
|
|
202
|
+
const PKBDF_SALT = keyFile.slice(6, 30);
|
|
203
|
+
const ENCRYPTION_NONCE = keyFile.slice(30, 54);
|
|
204
|
+
const ENCRYPTED_KEY = keyFile.slice(54);
|
|
205
|
+
const DERIVED_KEY = (0, node_crypto_1.pbkdf2Sync)(password, PKBDF_SALT, ITERATIONS, 32, "sha512");
|
|
206
|
+
const DECRYPTED_SIGNKEY = tweetnacl_1.default.secretbox.open(ENCRYPTED_KEY, ENCRYPTION_NONCE, new Uint8Array(DERIVED_KEY));
|
|
207
|
+
if (!DECRYPTED_SIGNKEY) {
|
|
208
|
+
throw new Error("Decryption failed. Wrong password?");
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
return XUtils.encodeHex(DECRYPTED_SIGNKEY);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
127
214
|
/**
|
|
128
215
|
* Decodes a hex string into a Uint8Array.
|
|
129
216
|
*
|
|
@@ -145,63 +232,6 @@ class XUtils {
|
|
|
145
232
|
}
|
|
146
233
|
}
|
|
147
234
|
exports.XUtils = XUtils;
|
|
148
|
-
XUtils.encodeUTF8 = utf8_1.decode;
|
|
149
|
-
XUtils.decodeUTF8 = utf8_1.encode;
|
|
150
|
-
XUtils.encodeBase64 = base64_1.encode;
|
|
151
|
-
XUtils.decodeBase64 = base64_1.decode;
|
|
152
|
-
/**
|
|
153
|
-
* Encrypts a secret key with a password and saves it as a file.
|
|
154
|
-
*
|
|
155
|
-
* @param path The path to save the keyfile.
|
|
156
|
-
* @param password The password to encrypt the keyfile with.
|
|
157
|
-
* @param keyToSave The key to encrypt.
|
|
158
|
-
* @param iterationOverride An optional override if you'd prefer to manually
|
|
159
|
-
* select your iterations rather than having a random amount selected.
|
|
160
|
-
*/
|
|
161
|
-
XUtils.saveKeyFile = (path, password, keyToSave, iterationOverride) => {
|
|
162
|
-
const UNENCRYPTED_SIGNKEY = XUtils.decodeHex(keyToSave);
|
|
163
|
-
const OFFSET = 1000;
|
|
164
|
-
// generate random amount of iterations
|
|
165
|
-
const R1 = tweetnacl_1.default.randomBytes(1);
|
|
166
|
-
const R2 = tweetnacl_1.default.randomBytes(1);
|
|
167
|
-
const N1 = XUtils.uint8ArrToNumber(R1);
|
|
168
|
-
const N2 = XUtils.uint8ArrToNumber(R2);
|
|
169
|
-
const iterations = iterationOverride
|
|
170
|
-
? iterationOverride
|
|
171
|
-
: N1 * N2 + OFFSET;
|
|
172
|
-
// length 6
|
|
173
|
-
const ITERATIONS = XUtils.numberToUint8Arr(iterations);
|
|
174
|
-
// length 24
|
|
175
|
-
const PKBDF_SALT = xMakeNonce();
|
|
176
|
-
// derived key to encrypt our signkeys with
|
|
177
|
-
const ENCRYPTION_KEY = Uint8Array.from(pbkdf2_1.pbkdf2Sync(password, PKBDF_SALT, iterations, 32));
|
|
178
|
-
const NONCE = xMakeNonce();
|
|
179
|
-
const ENCRYPTED_SIGNKEY = tweetnacl_1.default.secretbox(UNENCRYPTED_SIGNKEY, NONCE, ENCRYPTION_KEY);
|
|
180
|
-
fs_1.default.writeFileSync(path, xConcat(ITERATIONS, PKBDF_SALT, NONCE, ENCRYPTED_SIGNKEY));
|
|
181
|
-
};
|
|
182
|
-
/**
|
|
183
|
-
* Decrypts and returns a secret key stored in a file with saveKeyFile().
|
|
184
|
-
*
|
|
185
|
-
* @param path The path of the file.
|
|
186
|
-
* @param password The password the file was encrypted with.
|
|
187
|
-
*/
|
|
188
|
-
XUtils.loadKeyFile = (path, password) => {
|
|
189
|
-
const keyFile = Uint8Array.from(fs_1.default.readFileSync(path));
|
|
190
|
-
const ITERATIONS = XUtils.uint8ArrToNumber(keyFile.slice(0, 6));
|
|
191
|
-
const PKBDF_SALT = keyFile.slice(6, 30);
|
|
192
|
-
const ENCRYPTION_NONCE = keyFile.slice(30, 54);
|
|
193
|
-
// this is the id key we need to decrypt
|
|
194
|
-
const ENCRYPTED_KEY = keyFile.slice(54);
|
|
195
|
-
// the derived key from the user's password
|
|
196
|
-
const DERIVED_KEY = Uint8Array.from(pbkdf2_1.pbkdf2Sync(password, PKBDF_SALT, ITERATIONS, 32));
|
|
197
|
-
const DECRYPTED_SIGNKEY = tweetnacl_1.default.secretbox.open(ENCRYPTED_KEY, ENCRYPTION_NONCE, DERIVED_KEY);
|
|
198
|
-
if (!DECRYPTED_SIGNKEY) {
|
|
199
|
-
throw new Error("Decryption failed. Wrong password?");
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
return XUtils.encodeHex(DECRYPTED_SIGNKEY);
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
235
|
/**
|
|
206
236
|
* Gets a word list representation of a byte sequence.
|
|
207
237
|
*
|
|
@@ -211,7 +241,6 @@ XUtils.loadKeyFile = (path, password) => {
|
|
|
211
241
|
function xMnemonic(entropy, wordList) {
|
|
212
242
|
return bip39.entropyToMnemonic(Buffer.from(entropy), wordList);
|
|
213
243
|
}
|
|
214
|
-
exports.xMnemonic = xMnemonic;
|
|
215
244
|
/**
|
|
216
245
|
* Returns a 32 byte HMAC of a javscript object.
|
|
217
246
|
*
|
|
@@ -219,13 +248,12 @@ exports.xMnemonic = xMnemonic;
|
|
|
219
248
|
* @param SK the secret key to create the HMAC with
|
|
220
249
|
*/
|
|
221
250
|
function xHMAC(msg, SK) {
|
|
222
|
-
const packedMsg =
|
|
223
|
-
const hmacGen =
|
|
251
|
+
const packedMsg = packer.pack(msg);
|
|
252
|
+
const hmacGen = (0, node_crypto_1.createHmac)("sha256", Buffer.from(SK));
|
|
224
253
|
hmacGen.update(packedMsg);
|
|
225
254
|
const hmac = Uint8Array.from(hmacGen.digest());
|
|
226
255
|
return hmac;
|
|
227
256
|
}
|
|
228
|
-
exports.xHMAC = xHMAC;
|
|
229
257
|
/**
|
|
230
258
|
* Constants for vex.
|
|
231
259
|
*/
|
|
@@ -243,21 +271,24 @@ exports.xConstants = {
|
|
|
243
271
|
function xMakeNonce() {
|
|
244
272
|
return tweetnacl_1.default.randomBytes(24);
|
|
245
273
|
}
|
|
246
|
-
exports.xMakeNonce = xMakeNonce;
|
|
247
274
|
/**
|
|
248
275
|
* Derives a 32 byte secret key from some initial key material.
|
|
249
276
|
*
|
|
250
277
|
* @param IKM the initial key material.
|
|
251
278
|
* @returns The generated key.
|
|
252
279
|
*/
|
|
280
|
+
// export function xKDF(IKM: Uint8Array): Uint8Array {
|
|
281
|
+
// return Uint8Array.from(
|
|
282
|
+
// hkdf(Buffer.from(IKM), xConstants.KEY_LENGTH, {
|
|
283
|
+
// salt: Buffer.from(xMakeSalt(xConstants.CURVE)),
|
|
284
|
+
// info: xConstants.INFO,
|
|
285
|
+
// hash: xConstants.HASH,
|
|
286
|
+
// })
|
|
287
|
+
// );
|
|
288
|
+
// }
|
|
253
289
|
function xKDF(IKM) {
|
|
254
|
-
return Uint8Array
|
|
255
|
-
salt: Buffer.from(xMakeSalt(exports.xConstants.CURVE)),
|
|
256
|
-
info: exports.xConstants.INFO,
|
|
257
|
-
hash: exports.xConstants.HASH,
|
|
258
|
-
}));
|
|
290
|
+
return new Uint8Array((0, node_crypto_2.hkdfSync)("sha512", IKM, xMakeSalt(exports.xConstants.CURVE), exports.xConstants.INFO, exports.xConstants.KEY_LENGTH));
|
|
259
291
|
}
|
|
260
|
-
exports.xKDF = xKDF;
|
|
261
292
|
/**
|
|
262
293
|
* Hashes some data.
|
|
263
294
|
*
|
|
@@ -265,10 +296,9 @@ exports.xKDF = xKDF;
|
|
|
265
296
|
* @returns The hash of the data.
|
|
266
297
|
*/
|
|
267
298
|
function xHash(data) {
|
|
268
|
-
const hash =
|
|
299
|
+
const hash = (0, node_crypto_1.createHash)("sha512");
|
|
269
300
|
return hash.update(data).digest("hex");
|
|
270
301
|
}
|
|
271
|
-
exports.xHash = xHash;
|
|
272
302
|
/**
|
|
273
303
|
* Derives a shared Secret Key from a known private key and
|
|
274
304
|
* a peer's known public key.
|
|
@@ -280,14 +310,12 @@ exports.xHash = xHash;
|
|
|
280
310
|
function xDH(myPrivateKey, theirPublicKey) {
|
|
281
311
|
return tweetnacl_1.default.box.before(theirPublicKey, myPrivateKey);
|
|
282
312
|
}
|
|
283
|
-
exports.xDH = xDH;
|
|
284
313
|
/**
|
|
285
314
|
* Concatanates multiple Uint8Arrays.
|
|
286
315
|
*
|
|
287
316
|
* @param arrays As many Uint8Arrays as you would like to concatanate.
|
|
288
317
|
*/
|
|
289
318
|
function xConcat(...arrays) {
|
|
290
|
-
// sum of individual array lengths
|
|
291
319
|
const totalLength = arrays.reduce((acc, value) => acc + value.length, 0);
|
|
292
320
|
if (!arrays.length) {
|
|
293
321
|
return new Uint8Array();
|
|
@@ -302,7 +330,6 @@ function xConcat(...arrays) {
|
|
|
302
330
|
}
|
|
303
331
|
return result;
|
|
304
332
|
}
|
|
305
|
-
exports.xConcat = xConcat;
|
|
306
333
|
/**
|
|
307
334
|
* Encode an X25519 or X448 public key PK into a byte sequence.
|
|
308
335
|
* The encoding consists of 0 or 1 to represent the type of curve, followed by l
|
|
@@ -336,7 +363,6 @@ function xEncode(curveType, publicKey) {
|
|
|
336
363
|
}
|
|
337
364
|
return Uint8Array.from(bytes);
|
|
338
365
|
}
|
|
339
|
-
exports.xEncode = xEncode;
|
|
340
366
|
/**
|
|
341
367
|
* @ignore
|
|
342
368
|
*/
|
package/jest.config.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
// TODO: convert to es6 format
|
|
2
1
|
module.exports = {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
roots: ["<rootDir>/src"],
|
|
3
|
+
testMatch: [
|
|
4
|
+
"**/__tests__/**/*.+(ts|tsx|js)",
|
|
5
|
+
"**/?(*.)+(spec|test).+(ts|tsx|js)",
|
|
6
|
+
],
|
|
7
|
+
transform: {
|
|
8
|
+
"^.+\\.(ts|tsx)$": [
|
|
9
|
+
"ts-jest",
|
|
10
|
+
{
|
|
11
|
+
diagnostics: false,
|
|
12
|
+
isolatedModules: true,
|
|
13
|
+
},
|
|
5
14
|
],
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"**/?(*.)+(spec|test).+(ts|tsx|js)"
|
|
9
|
-
],
|
|
10
|
-
"transform": {
|
|
11
|
-
"^.+\\.(ts|tsx)$": "ts-jest"
|
|
12
|
-
},
|
|
13
|
-
}
|
|
15
|
+
},
|
|
16
|
+
};
|
package/mise.toml
ADDED
package/package.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"husky":
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
2
|
+
"name": "@vex-chat/crypto",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Crypto primitives for Vex",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"author": "Extra <extrahash@protonmail.com>",
|
|
8
|
+
"license": "AGPL-3.0-or-later",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "rimraf dist && tsc",
|
|
11
|
+
"prepack": "yarn build",
|
|
12
|
+
"prettier": "prettier '**/*.{ts,tsx,json,md}' --ignore-path .gitignore --write",
|
|
13
|
+
"lint": "eslint src/**/*.ts",
|
|
14
|
+
"lint-fix": "eslint src/**/*.ts --fix",
|
|
15
|
+
"push": "yarn build && yalc push",
|
|
16
|
+
"prepublish": "yarn build",
|
|
17
|
+
"test": "npx jest --runInBand --forceExit"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@stablelib/base64": "^1.0.1",
|
|
21
|
+
"@stablelib/utf8": "^1.0.1",
|
|
22
|
+
"@vex-chat/types": "^0.11.0",
|
|
23
|
+
"bip39": "^3.1.0",
|
|
24
|
+
"ed2curve": "^0.3.0",
|
|
25
|
+
"msgpackr": "^1.10.1",
|
|
26
|
+
"tweetnacl": "^1.0.3",
|
|
27
|
+
"uuid": "^9.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/create-hmac": "^1.1.3",
|
|
31
|
+
"@types/ed2curve": "^0.2.4",
|
|
32
|
+
"@types/jest": "^30.0.0",
|
|
33
|
+
"@types/lodash": "^4.17.21",
|
|
34
|
+
"@types/node": "^25.0.3",
|
|
35
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
36
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
37
|
+
"eslint": "^9.0.0",
|
|
38
|
+
"eslint-config-prettier": "^9.0.0",
|
|
39
|
+
"husky": "^9.0.0",
|
|
40
|
+
"jest": "^30.2.0",
|
|
41
|
+
"lint-staged": "^15.2.0",
|
|
42
|
+
"lodash": "^4.17.21",
|
|
43
|
+
"prettier": "^3.2.0",
|
|
44
|
+
"rimraf": "^5.0.0",
|
|
45
|
+
"ts-jest": "^29.4.6",
|
|
46
|
+
"typescript": "^5.7.0",
|
|
47
|
+
"@changesets/cli": "^2.29.8"
|
|
48
|
+
},
|
|
49
|
+
"lint-staged": {
|
|
50
|
+
"src/**/*.{ts}": [
|
|
51
|
+
"eslint --fix"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/vex-chat/libvex-js.git"
|
|
57
|
+
},
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/vex-chat/libvex-js/issues"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/vex-chat/libvex-js#readme"
|
|
62
62
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
// tslint:disable-next-line: no-implicit-dependencies
|
|
7
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
-
const __1 = require("..");
|
|
9
|
-
const ed25519Keys = {
|
|
10
|
-
public: "8d0538a45bce3d6fd43cd80a247da063c67cd01da2e263758567a51db5b1f7c6",
|
|
11
|
-
private: "f69c92fbb224e1d75c5dffb5e40946e6106baa89ad73dbb6ef0bec2d8562d8a28d0538a45bce3d6fd43cd80a247da063c67cd01da2e263758567a51db5b1f7c6",
|
|
12
|
-
};
|
|
13
|
-
const convertedX25519Keys = {
|
|
14
|
-
public: "55c4ca5a1d8e2859e186f36564cc41c9c9882ed9dbc01be8ec9a36b106eeee5b",
|
|
15
|
-
private: "10ed501acc2125730c294aa4b78eac989588d031015d1c77a75ea98aa7744b7a",
|
|
16
|
-
};
|
|
17
|
-
test("convertKeyPair", () => {
|
|
18
|
-
const keys = keyPairFromString(ed25519Keys);
|
|
19
|
-
const converted = __1.XKeyConvert.convertKeyPair(keys);
|
|
20
|
-
expect(lodash_1.default.isEqual(converted, keyPairFromString(convertedX25519Keys))).toBe(true);
|
|
21
|
-
});
|
|
22
|
-
test("convertPublicKey", () => {
|
|
23
|
-
const keys = keyPairFromString(ed25519Keys);
|
|
24
|
-
const convertedPublicKey = __1.XKeyConvert.convertPublicKey(keys.publicKey);
|
|
25
|
-
if (!convertedPublicKey) {
|
|
26
|
-
throw new Error("Conversion failed.");
|
|
27
|
-
}
|
|
28
|
-
const correctConvertedKey = __1.XUtils.decodeHex(convertedX25519Keys.public);
|
|
29
|
-
expect(__1.XUtils.bytesEqual(convertedPublicKey, correctConvertedKey)).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
test("convertPrivateKey", () => {
|
|
32
|
-
const keys = keyPairFromString(ed25519Keys);
|
|
33
|
-
const convertedPrivateKey = __1.XKeyConvert.convertSecretKey(keys.secretKey);
|
|
34
|
-
if (!convertedPrivateKey) {
|
|
35
|
-
throw new Error("Conversion failed.");
|
|
36
|
-
}
|
|
37
|
-
const correctConvertedKey = __1.XUtils.decodeHex(convertedX25519Keys.private);
|
|
38
|
-
expect(__1.XUtils.bytesEqual(convertedPrivateKey, correctConvertedKey)).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
function keyPairToString(keyPair) {
|
|
41
|
-
return {
|
|
42
|
-
public: __1.XUtils.encodeHex(keyPair.publicKey),
|
|
43
|
-
private: __1.XUtils.encodeHex(keyPair.secretKey),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function keyPairFromString(strKeyPair) {
|
|
47
|
-
return {
|
|
48
|
-
publicKey: __1.XUtils.decodeHex(strKeyPair.public),
|
|
49
|
-
secretKey: __1.XUtils.decodeHex(strKeyPair.private),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../../index");
|
|
4
|
-
const { bytesEqual } = index_1.XUtils;
|
|
5
|
-
test("bytesEqual", () => {
|
|
6
|
-
const bytes = [25, 23, 122, 142, 73, 92, 58];
|
|
7
|
-
const buf1 = Buffer.from(bytes);
|
|
8
|
-
const buf2 = Buffer.from(bytes);
|
|
9
|
-
expect(bytesEqual(buf1, buf2)).toBe(true);
|
|
10
|
-
bytes[0] = 0;
|
|
11
|
-
const buf3 = Buffer.from(bytes);
|
|
12
|
-
expect(bytesEqual(buf1, buf3)).toBe(false);
|
|
13
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../../index");
|
|
4
|
-
const { emptyHeader } = index_1.XUtils;
|
|
5
|
-
test("emptyHeader", () => {
|
|
6
|
-
const headerData = "0000000000000000000000000000000000000000000000000000000000000000";
|
|
7
|
-
const eHeader = emptyHeader();
|
|
8
|
-
const testEmptyHeader = index_1.XUtils.decodeHex(headerData);
|
|
9
|
-
expect(index_1.XUtils.bytesEqual(eHeader, testEmptyHeader)).toBe(true);
|
|
10
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const index_1 = require("../../index");
|
|
7
|
-
const { saveKeyFile, loadKeyFile } = index_1.XUtils;
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
test("Save a key and reload it", () => {
|
|
10
|
-
const secretKey = "86fbed70aa300a523979a318799d6d523a6cb4c84bfb865d3a3e52a568ec6a63560eeaae57a57d62668898355c2218b142d6069bf9f53a00b5c3c46dd257c4dc";
|
|
11
|
-
const password = "hunter2";
|
|
12
|
-
const fileName = "test.keyfile";
|
|
13
|
-
saveKeyFile(fileName, password, secretKey);
|
|
14
|
-
const decryptedKey = loadKeyFile(fileName, password);
|
|
15
|
-
expect(secretKey === decryptedKey).toBe(true);
|
|
16
|
-
// cleanup the file
|
|
17
|
-
fs_1.default.unlinkSync(fileName);
|
|
18
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../../index");
|
|
4
|
-
const { numberToUint8Arr, bytesEqual } = index_1.XUtils;
|
|
5
|
-
test("numberToUint8Arr", () => {
|
|
6
|
-
const numbers = [
|
|
7
|
-
255,
|
|
8
|
-
65535,
|
|
9
|
-
16777215,
|
|
10
|
-
4294967295,
|
|
11
|
-
1099511627775,
|
|
12
|
-
281474976710655,
|
|
13
|
-
];
|
|
14
|
-
const buffers = [
|
|
15
|
-
[0, 0, 0, 0, 0, 255],
|
|
16
|
-
[0, 0, 0, 0, 255, 255],
|
|
17
|
-
[0, 0, 0, 255, 255, 255],
|
|
18
|
-
[0, 0, 255, 255, 255, 255],
|
|
19
|
-
[0, 255, 255, 255, 255, 255],
|
|
20
|
-
[255, 255, 255, 255, 255, 255],
|
|
21
|
-
];
|
|
22
|
-
// tslint:disable-next-line: prefer-for-of
|
|
23
|
-
for (let i = 0; i < numbers.length; i++) {
|
|
24
|
-
const arr = numberToUint8Arr(numbers[i]);
|
|
25
|
-
expect(bytesEqual(arr, Buffer.from(buffers[i]))).toBe(true);
|
|
26
|
-
}
|
|
27
|
-
expect(() => numberToUint8Arr(281474976710656)).toThrow();
|
|
28
|
-
expect(() => numberToUint8Arr(-1)).toThrow();
|
|
29
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../../index");
|
|
4
|
-
const { packMessage, emptyHeader } = index_1.XUtils;
|
|
5
|
-
test("packMessage", () => {
|
|
6
|
-
const testMessage = {
|
|
7
|
-
type: "resource",
|
|
8
|
-
resourceType: "server",
|
|
9
|
-
action: "create",
|
|
10
|
-
transmissionID: "8154ac29-54fb-407c-8353-0f67742bb7c4",
|
|
11
|
-
data: "A Server Name",
|
|
12
|
-
};
|
|
13
|
-
const packedTestMessage = "000000000000000000000000000000000000000000000000000000000000000085a474797065a87265736f75726365ac7265736f7572636554797065a6736572766572a6616374696f6ea6637265617465ae7472616e736d697373696f6e4944d92438313534616332392d353466622d343037632d383335332d306636373734326262376334a464617461ad4120536572766572204e616d65";
|
|
14
|
-
const packedMessage = index_1.XUtils.encodeHex(packMessage(testMessage, emptyHeader()));
|
|
15
|
-
expect(packedTestMessage === packedMessage).toBe(true);
|
|
16
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../../index");
|
|
4
|
-
const { encodeHex, decodeHex, encodeUTF8, decodeUTF8, encodeBase64, decodeBase64, } = index_1.XUtils;
|
|
5
|
-
test("Encodes and decodes hex", () => {
|
|
6
|
-
const data = [
|
|
7
|
-
"a2dc693b93b3e2a31eb2b54f26f43b8ce971c6b9b4197544",
|
|
8
|
-
"9d9158ea82750c0b164834789f216d5a17a223d87e082199",
|
|
9
|
-
"e32079ba7c8ed5e62123ab55386689c2ec9f480ebb82f05c",
|
|
10
|
-
"e037b3f87bea23b8afea27c7ad173f5a43d0050559fbe091",
|
|
11
|
-
"df3cefb0f980f96eb5d6cc996702d6d166413fb2785772b1",
|
|
12
|
-
"6a328c1b103d1b331c9759ddde6c5df5753010a3c9881514",
|
|
13
|
-
"c5ad6470766845c420205700aaaed806456cae49b905aeed",
|
|
14
|
-
"5dc12b62156b1f68698b36b42e3e2f4716dffee09b768030",
|
|
15
|
-
"2985705f1f590b11e027ea6a05cbe4e0d351ab81748cbea0",
|
|
16
|
-
"6455945ea7110197a17a809cb973c2007eff629d5549273a",
|
|
17
|
-
];
|
|
18
|
-
for (const value of data) {
|
|
19
|
-
expect(encodeHex(decodeHex(value)) === value).toBe(true);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
test("Encodes and decodes utf8", () => {
|
|
23
|
-
const data = [
|
|
24
|
-
"L-dr`?%z5%?R8rT:Lwvk",
|
|
25
|
-
"H]gy!'X\")(:V/3.'LpE/",
|
|
26
|
-
"5G%h:@%PvCOk R,[]=z>",
|
|
27
|
-
'#d868evg)LM"{04$gFt',
|
|
28
|
-
'?\\/sz?&mh"$!K1_`qc15',
|
|
29
|
-
"V{Yw[ R{5L}1T3OHSj.",
|
|
30
|
-
"%-Kek[HIfW=_z`r'R|Av",
|
|
31
|
-
"E.E'\"\\ jzyxpfc'.N*z`",
|
|
32
|
-
"p:&^?<[n<ScUXB#O=|z",
|
|
33
|
-
'D;`5`"@H7X8Iw0%KbJr8',
|
|
34
|
-
'#,y][nQ9]",.62Bwxj#d',
|
|
35
|
-
'[eN"USyz$Dg@%a=a)r2h',
|
|
36
|
-
];
|
|
37
|
-
for (const value of data) {
|
|
38
|
-
expect(encodeUTF8(decodeUTF8(value))).toBe(value);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
test("Encodes and decodes base64", () => {
|
|
42
|
-
const data = [
|
|
43
|
-
"+UMP/v5VnVF/qSrSDfcLAXZ9jEauYFrbAcgtE3z46bI=",
|
|
44
|
-
"Cb+zq/R1zMRSEMGA1p47XWzwD48NZ/JqLO1p1hUnpEY=",
|
|
45
|
-
"mODgEB/U3MnvMHuG5fQ0xv8NRqo24diRlzyzJ4/Et7g=",
|
|
46
|
-
"vvYVuOpi3/pMdP49C7TgTqEdk02/LlcIY9a0CPyOJsc=",
|
|
47
|
-
"S6vBIf8WXmPi/BPV3ei9CMgdanxBNiTl8oHQ/HSnvsU=",
|
|
48
|
-
"0i2WNMF8I5ewIAefTbBBjhS3sZwZ9tILLpksPE00bt8=",
|
|
49
|
-
"W3SHYUb/F3sWFytIYNG4TCBgrDT80L0A9bB335nU8/8=",
|
|
50
|
-
"vbov+TNLyWc+VdpH7egFOifdKup26ertUlutTv8kFyY=",
|
|
51
|
-
"re9JVfQRSsXaaUG9uLoMd/bW05xDcCnk0qaPh6CUn90=",
|
|
52
|
-
"X9AyjBOM9tAsXrINjeDr5wgMiZNlkK5HlOOtDBwMeFw=",
|
|
53
|
-
];
|
|
54
|
-
for (const value of data) {
|
|
55
|
-
expect(encodeBase64(decodeBase64(value)) === value).toBe(true);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../../index");
|
|
4
|
-
const { uint8ArrToNumber, bytesEqual } = index_1.XUtils;
|
|
5
|
-
test("uint8ArrToNumber", () => {
|
|
6
|
-
const numbers = [
|
|
7
|
-
255,
|
|
8
|
-
65535,
|
|
9
|
-
16777215,
|
|
10
|
-
4294967295,
|
|
11
|
-
1099511627775,
|
|
12
|
-
281474976710655,
|
|
13
|
-
];
|
|
14
|
-
const buffers = [
|
|
15
|
-
[0, 0, 0, 0, 0, 255],
|
|
16
|
-
[0, 0, 0, 0, 255, 255],
|
|
17
|
-
[0, 0, 0, 255, 255, 255],
|
|
18
|
-
[0, 0, 255, 255, 255, 255],
|
|
19
|
-
[0, 255, 255, 255, 255, 255],
|
|
20
|
-
[255, 255, 255, 255, 255, 255],
|
|
21
|
-
];
|
|
22
|
-
// tslint:disable-next-line: prefer-for-of
|
|
23
|
-
for (let i = 0; i < numbers.length; i++) {
|
|
24
|
-
const num1 = uint8ArrToNumber(Buffer.from(buffers[i]));
|
|
25
|
-
const num2 = numbers[i];
|
|
26
|
-
expect(num1 === num2).toBe(true);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
// tslint:disable-next-line: no-implicit-dependencies
|
|
7
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
-
const index_1 = require("../../index");
|
|
9
|
-
const { unpackMessage, emptyHeader, bytesEqual } = index_1.XUtils;
|
|
10
|
-
test("packMessage", () => {
|
|
11
|
-
const testHeader = emptyHeader();
|
|
12
|
-
const testMessage = {
|
|
13
|
-
type: "resource",
|
|
14
|
-
resourceType: "server",
|
|
15
|
-
action: "create",
|
|
16
|
-
transmissionID: "8154ac29-54fb-407c-8353-0f67742bb7c4",
|
|
17
|
-
data: "A Server Name",
|
|
18
|
-
};
|
|
19
|
-
const packedTestMessage = "000000000000000000000000000000000000000000000000000000000000000085a474797065a87265736f75726365ac7265736f7572636554797065a6736572766572a6616374696f6ea6637265617465ae7472616e736d697373696f6e4944d92438313534616332392d353466622d343037632d383335332d306636373734326262376334a464617461ad4120536572766572204e616d65";
|
|
20
|
-
const messageData = index_1.XUtils.decodeHex(packedTestMessage);
|
|
21
|
-
const [unpackedHeader, unpackedMessage] = unpackMessage(messageData);
|
|
22
|
-
expect(bytesEqual(unpackedHeader, testHeader)).toBe(true);
|
|
23
|
-
expect(lodash_1.default.isEqual(testMessage, unpackedMessage)).toBe(true);
|
|
24
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const __1 = require("..");
|
|
4
|
-
test("xConcat", () => {
|
|
5
|
-
const data1 = "dead";
|
|
6
|
-
const data2 = "beef";
|
|
7
|
-
const data3 = "bead";
|
|
8
|
-
const correctConcatData = data1 + data2 + data3;
|
|
9
|
-
const concatData = __1.XUtils.encodeHex(__1.xConcat(__1.XUtils.decodeHex(data1), __1.XUtils.decodeHex(data2), __1.XUtils.decodeHex(data3)));
|
|
10
|
-
expect(concatData === correctConcatData).toBe(true);
|
|
11
|
-
});
|
package/dist/__tests__/xDH.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/__tests__/xDH.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const __1 = require("..");
|
|
4
|
-
test("xDH", () => {
|
|
5
|
-
const myPrivateKey = "918ed243e2c6c507168b20e8b167cff33a10c30e99e8defe28dc2147f5cce703";
|
|
6
|
-
const theirPublicKey = "6f4cc1ffc4009bd4f94628ba5922e40afa3491f0daa43ec9da0f7dc39bb1c026";
|
|
7
|
-
const correctDerivedKey = "19a8594bdcf875ec9d4b8b9615ea8b73a0b327bb64b8f727dd2dee3a603a2230";
|
|
8
|
-
const derivedKey = __1.XUtils.encodeHex(__1.xDH(__1.XUtils.decodeHex(myPrivateKey), __1.XUtils.decodeHex(theirPublicKey)));
|
|
9
|
-
expect(correctDerivedKey === derivedKey).toBe(true);
|
|
10
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const __1 = require("..");
|
|
4
|
-
test("xEncode", () => {
|
|
5
|
-
const PK = "3a488fc006156e77e58793846c204f17e0df88e914fc7638a084524a9124bf87";
|
|
6
|
-
const correctEncoded = "00013a488fc006156e77e58793846c204f17e0df88e914fc7638a084524a9124bf87";
|
|
7
|
-
const encoded = __1.XUtils.encodeHex(__1.xEncode("X25519", __1.XUtils.decodeHex(PK)));
|
|
8
|
-
expect(encoded === correctEncoded).toBe(true);
|
|
9
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/__tests__/xHMAC.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const __1 = require("..");
|
|
4
|
-
test("xHMAC", () => {
|
|
5
|
-
const message = {
|
|
6
|
-
hello: "world",
|
|
7
|
-
};
|
|
8
|
-
const SK = "b45203ef77c0a7fe7f771297f3e5c8248fe5b9f18ecf77faf8a8cef1058e630a";
|
|
9
|
-
const correctHMAC = "a9b398cb69d356f0376c3ec78bc16aa885fdf3cd5be2203f0cc15a3340f3b0fe";
|
|
10
|
-
const hmac = __1.XUtils.encodeHex(__1.xHMAC(message, __1.XUtils.decodeHex(SK)));
|
|
11
|
-
expect(correctHMAC === hmac).toBe(true);
|
|
12
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const __1 = require("..");
|
|
4
|
-
test("xMnemonic", () => {
|
|
5
|
-
const IKM = "dfb3c08de7335cc352e2c063c8e6891a06e17bf0dfcb4eec8139fc5eaf482b0e";
|
|
6
|
-
const correctMnemonic = "text own casino solar cupboard giant entire fix glow elbow pelican cross host sadness sell west exclude goat example weather turtle piano promote scene";
|
|
7
|
-
const mnemonic = __1.xMnemonic(__1.XUtils.decodeHex(IKM));
|
|
8
|
-
expect(mnemonic === correctMnemonic).toBe(true);
|
|
9
|
-
});
|