@vex-chat/crypto 0.7.18 → 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 +13 -7
- package/dist/index.js +125 -87
- package/jest.config.js +14 -11
- package/mise.toml +3 -0
- package/package.json +60 -58
- 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
|
*/
|
|
@@ -122,6 +121,13 @@ export declare function xMakeNonce(): Uint8Array;
|
|
|
122
121
|
* @returns The generated key.
|
|
123
122
|
*/
|
|
124
123
|
export declare function xKDF(IKM: Uint8Array): Uint8Array;
|
|
124
|
+
/**
|
|
125
|
+
* Hashes some data.
|
|
126
|
+
*
|
|
127
|
+
* @param data the data to hash.
|
|
128
|
+
* @returns The hash of the data.
|
|
129
|
+
*/
|
|
130
|
+
export declare function xHash(data: Uint8Array): string;
|
|
125
131
|
/**
|
|
126
132
|
* Derives a shared Secret Key from a known private key and
|
|
127
133
|
* a peer's known public key.
|
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,28 +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"));
|
|
57
|
+
const packer = new msgpackr_1.Packr({
|
|
58
|
+
useRecords: false,
|
|
59
|
+
moreTypes: true,
|
|
60
|
+
});
|
|
36
61
|
/**
|
|
37
62
|
* Provides an interface that can map an ed25519 keypair to its equivalent
|
|
38
63
|
* X25519 keypair.
|
|
@@ -43,6 +68,10 @@ exports.XKeyConvert = ed2curve_1.default;
|
|
|
43
68
|
* vex messages.
|
|
44
69
|
*/
|
|
45
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;
|
|
46
75
|
/**
|
|
47
76
|
* Checks if two buffer-like objects are equal.
|
|
48
77
|
*
|
|
@@ -101,7 +130,8 @@ class XUtils {
|
|
|
101
130
|
static unpackMessage(msg) {
|
|
102
131
|
const msgp = Uint8Array.from(msg);
|
|
103
132
|
const msgh = msgp.slice(0, exports.xConstants.HEADER_SIZE);
|
|
104
|
-
|
|
133
|
+
// UPDATED: Use msgpackr
|
|
134
|
+
const msgb = packer.unpack(msgp.slice(exports.xConstants.HEADER_SIZE));
|
|
105
135
|
return [msgh, msgb];
|
|
106
136
|
}
|
|
107
137
|
/**
|
|
@@ -111,7 +141,8 @@ class XUtils {
|
|
|
111
141
|
* @returns the packed message.
|
|
112
142
|
*/
|
|
113
143
|
static packMessage(msg, header) {
|
|
114
|
-
|
|
144
|
+
// UPDATED: Use msgpackr
|
|
145
|
+
const msgb = packer.pack(msg);
|
|
115
146
|
const msgh = header || XUtils.emptyHeader();
|
|
116
147
|
return xConcat(msgh, msgb);
|
|
117
148
|
}
|
|
@@ -123,6 +154,63 @@ class XUtils {
|
|
|
123
154
|
static emptyHeader() {
|
|
124
155
|
return new Uint8Array(exports.xConstants.HEADER_SIZE);
|
|
125
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
|
+
};
|
|
126
214
|
/**
|
|
127
215
|
* Decodes a hex string into a Uint8Array.
|
|
128
216
|
*
|
|
@@ -144,63 +232,6 @@ class XUtils {
|
|
|
144
232
|
}
|
|
145
233
|
}
|
|
146
234
|
exports.XUtils = XUtils;
|
|
147
|
-
XUtils.encodeUTF8 = utf8_1.decode;
|
|
148
|
-
XUtils.decodeUTF8 = utf8_1.encode;
|
|
149
|
-
XUtils.encodeBase64 = base64_1.encode;
|
|
150
|
-
XUtils.decodeBase64 = base64_1.decode;
|
|
151
|
-
/**
|
|
152
|
-
* Encrypts a secret key with a password and saves it as a file.
|
|
153
|
-
*
|
|
154
|
-
* @param path The path to save the keyfile.
|
|
155
|
-
* @param password The password to encrypt the keyfile with.
|
|
156
|
-
* @param keyToSave The key to encrypt.
|
|
157
|
-
* @param iterationOverride An optional override if you'd prefer to manually
|
|
158
|
-
* select your iterations rather than having a random amount selected.
|
|
159
|
-
*/
|
|
160
|
-
XUtils.saveKeyFile = (path, password, keyToSave, iterationOverride) => {
|
|
161
|
-
const UNENCRYPTED_SIGNKEY = XUtils.decodeHex(keyToSave);
|
|
162
|
-
const OFFSET = 1000;
|
|
163
|
-
// generate random amount of iterations
|
|
164
|
-
const R1 = tweetnacl_1.default.randomBytes(1);
|
|
165
|
-
const R2 = tweetnacl_1.default.randomBytes(1);
|
|
166
|
-
const N1 = XUtils.uint8ArrToNumber(R1);
|
|
167
|
-
const N2 = XUtils.uint8ArrToNumber(R2);
|
|
168
|
-
const iterations = iterationOverride
|
|
169
|
-
? iterationOverride
|
|
170
|
-
: N1 * N2 + OFFSET;
|
|
171
|
-
// length 6
|
|
172
|
-
const ITERATIONS = XUtils.numberToUint8Arr(iterations);
|
|
173
|
-
// length 24
|
|
174
|
-
const PKBDF_SALT = xMakeNonce();
|
|
175
|
-
// derived key to encrypt our signkeys with
|
|
176
|
-
const ENCRYPTION_KEY = Uint8Array.from(pbkdf2_1.pbkdf2Sync(password, PKBDF_SALT, iterations, 32));
|
|
177
|
-
const NONCE = xMakeNonce();
|
|
178
|
-
const ENCRYPTED_SIGNKEY = tweetnacl_1.default.secretbox(UNENCRYPTED_SIGNKEY, NONCE, ENCRYPTION_KEY);
|
|
179
|
-
fs_1.default.writeFileSync(path, xConcat(ITERATIONS, PKBDF_SALT, NONCE, ENCRYPTED_SIGNKEY));
|
|
180
|
-
};
|
|
181
|
-
/**
|
|
182
|
-
* Decrypts and returns a secret key stored in a file with saveKeyFile().
|
|
183
|
-
*
|
|
184
|
-
* @param path The path of the file.
|
|
185
|
-
* @param password The password the file was encrypted with.
|
|
186
|
-
*/
|
|
187
|
-
XUtils.loadKeyFile = (path, password) => {
|
|
188
|
-
const keyFile = Uint8Array.from(fs_1.default.readFileSync(path));
|
|
189
|
-
const ITERATIONS = XUtils.uint8ArrToNumber(keyFile.slice(0, 6));
|
|
190
|
-
const PKBDF_SALT = keyFile.slice(6, 30);
|
|
191
|
-
const ENCRYPTION_NONCE = keyFile.slice(30, 54);
|
|
192
|
-
// this is the id key we need to decrypt
|
|
193
|
-
const ENCRYPTED_KEY = keyFile.slice(54);
|
|
194
|
-
// the derived key from the user's password
|
|
195
|
-
const DERIVED_KEY = Uint8Array.from(pbkdf2_1.pbkdf2Sync(password, PKBDF_SALT, ITERATIONS, 32));
|
|
196
|
-
const DECRYPTED_SIGNKEY = tweetnacl_1.default.secretbox.open(ENCRYPTED_KEY, ENCRYPTION_NONCE, DERIVED_KEY);
|
|
197
|
-
if (!DECRYPTED_SIGNKEY) {
|
|
198
|
-
throw new Error("Decryption failed. Wrong password?");
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
return XUtils.encodeHex(DECRYPTED_SIGNKEY);
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
235
|
/**
|
|
205
236
|
* Gets a word list representation of a byte sequence.
|
|
206
237
|
*
|
|
@@ -210,7 +241,6 @@ XUtils.loadKeyFile = (path, password) => {
|
|
|
210
241
|
function xMnemonic(entropy, wordList) {
|
|
211
242
|
return bip39.entropyToMnemonic(Buffer.from(entropy), wordList);
|
|
212
243
|
}
|
|
213
|
-
exports.xMnemonic = xMnemonic;
|
|
214
244
|
/**
|
|
215
245
|
* Returns a 32 byte HMAC of a javscript object.
|
|
216
246
|
*
|
|
@@ -218,13 +248,12 @@ exports.xMnemonic = xMnemonic;
|
|
|
218
248
|
* @param SK the secret key to create the HMAC with
|
|
219
249
|
*/
|
|
220
250
|
function xHMAC(msg, SK) {
|
|
221
|
-
const packedMsg =
|
|
222
|
-
const hmacGen =
|
|
251
|
+
const packedMsg = packer.pack(msg);
|
|
252
|
+
const hmacGen = (0, node_crypto_1.createHmac)("sha256", Buffer.from(SK));
|
|
223
253
|
hmacGen.update(packedMsg);
|
|
224
254
|
const hmac = Uint8Array.from(hmacGen.digest());
|
|
225
255
|
return hmac;
|
|
226
256
|
}
|
|
227
|
-
exports.xHMAC = xHMAC;
|
|
228
257
|
/**
|
|
229
258
|
* Constants for vex.
|
|
230
259
|
*/
|
|
@@ -242,21 +271,34 @@ exports.xConstants = {
|
|
|
242
271
|
function xMakeNonce() {
|
|
243
272
|
return tweetnacl_1.default.randomBytes(24);
|
|
244
273
|
}
|
|
245
|
-
exports.xMakeNonce = xMakeNonce;
|
|
246
274
|
/**
|
|
247
275
|
* Derives a 32 byte secret key from some initial key material.
|
|
248
276
|
*
|
|
249
277
|
* @param IKM the initial key material.
|
|
250
278
|
* @returns The generated key.
|
|
251
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
|
+
// }
|
|
252
289
|
function xKDF(IKM) {
|
|
253
|
-
return Uint8Array
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
290
|
+
return new Uint8Array((0, node_crypto_2.hkdfSync)("sha512", IKM, xMakeSalt(exports.xConstants.CURVE), exports.xConstants.INFO, exports.xConstants.KEY_LENGTH));
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Hashes some data.
|
|
294
|
+
*
|
|
295
|
+
* @param data the data to hash.
|
|
296
|
+
* @returns The hash of the data.
|
|
297
|
+
*/
|
|
298
|
+
function xHash(data) {
|
|
299
|
+
const hash = (0, node_crypto_1.createHash)("sha512");
|
|
300
|
+
return hash.update(data).digest("hex");
|
|
258
301
|
}
|
|
259
|
-
exports.xKDF = xKDF;
|
|
260
302
|
/**
|
|
261
303
|
* Derives a shared Secret Key from a known private key and
|
|
262
304
|
* a peer's known public key.
|
|
@@ -268,14 +310,12 @@ exports.xKDF = xKDF;
|
|
|
268
310
|
function xDH(myPrivateKey, theirPublicKey) {
|
|
269
311
|
return tweetnacl_1.default.box.before(theirPublicKey, myPrivateKey);
|
|
270
312
|
}
|
|
271
|
-
exports.xDH = xDH;
|
|
272
313
|
/**
|
|
273
314
|
* Concatanates multiple Uint8Arrays.
|
|
274
315
|
*
|
|
275
316
|
* @param arrays As many Uint8Arrays as you would like to concatanate.
|
|
276
317
|
*/
|
|
277
318
|
function xConcat(...arrays) {
|
|
278
|
-
// sum of individual array lengths
|
|
279
319
|
const totalLength = arrays.reduce((acc, value) => acc + value.length, 0);
|
|
280
320
|
if (!arrays.length) {
|
|
281
321
|
return new Uint8Array();
|
|
@@ -290,7 +330,6 @@ function xConcat(...arrays) {
|
|
|
290
330
|
}
|
|
291
331
|
return result;
|
|
292
332
|
}
|
|
293
|
-
exports.xConcat = xConcat;
|
|
294
333
|
/**
|
|
295
334
|
* Encode an X25519 or X448 public key PK into a byte sequence.
|
|
296
335
|
* The encoding consists of 0 or 1 to represent the type of curve, followed by l
|
|
@@ -324,7 +363,6 @@ function xEncode(curveType, publicKey) {
|
|
|
324
363
|
}
|
|
325
364
|
return Uint8Array.from(bytes);
|
|
326
365
|
}
|
|
327
|
-
exports.xEncode = xEncode;
|
|
328
366
|
/**
|
|
329
367
|
* @ignore
|
|
330
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,60 +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
|
-
|
|
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"
|
|
60
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
|
-
});
|