├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ └── build-linux.yml
├── .gitignore
├── .huskyrc.json
├── .lintstagedrc.json
├── .prettierrc.json
├── LICENSE
├── README.md
├── benchmark
├── README.md
├── benchmark.js
├── browser.js
├── index.html
├── index.js
├── package.json
└── webpack.config.js
├── examples
└── webpack
│ ├── package.json
│ ├── src
│ ├── index.html
│ └── index.js
│ └── webpack.config.js
├── guides
├── create-react-app.md
├── react-native.md
├── umd.md
├── usage-examples.md
└── webpack.md
├── lerna.json
├── package.json
├── packages
├── core-foundation
│ ├── browser.asmjs.cjs.js
│ ├── browser.asmjs.es.js
│ ├── browser.cjs.js
│ ├── browser.es.js
│ ├── index.d.ts
│ ├── libfoundation.browser.wasm
│ ├── libfoundation.wasm
│ ├── libfoundation.worker.wasm
│ ├── node.asmjs.cjs.js
│ ├── node.asmjs.es.js
│ ├── node.cjs.js
│ ├── node.es.js
│ ├── package.json
│ ├── worker.asmjs.cjs.js
│ ├── worker.asmjs.es.js
│ ├── worker.cjs.js
│ └── worker.es.js
├── core-phe
│ ├── browser.asmjs.cjs.js
│ ├── browser.asmjs.es.js
│ ├── browser.cjs.js
│ ├── browser.es.js
│ ├── index.d.ts
│ ├── libphe.browser.wasm
│ ├── libphe.wasm
│ ├── libphe.worker.wasm
│ ├── node.asmjs.cjs.js
│ ├── node.asmjs.es.js
│ ├── node.cjs.js
│ ├── node.es.js
│ ├── package.json
│ ├── worker.asmjs.cjs.js
│ ├── worker.asmjs.es.js
│ ├── worker.cjs.js
│ └── worker.es.js
├── core-pythia
│ ├── browser.asmjs.cjs.js
│ ├── browser.asmjs.es.js
│ ├── browser.cjs.js
│ ├── browser.es.js
│ ├── index.d.ts
│ ├── libpythia.browser.wasm
│ ├── libpythia.wasm
│ ├── libpythia.worker.wasm
│ ├── node.asmjs.cjs.js
│ ├── node.asmjs.es.js
│ ├── node.cjs.js
│ ├── node.es.js
│ ├── package.json
│ ├── worker.asmjs.cjs.js
│ ├── worker.asmjs.es.js
│ ├── worker.cjs.js
│ └── worker.es.js
├── core-ratchet
│ ├── browser.asmjs.cjs.js
│ ├── browser.asmjs.es.js
│ ├── browser.cjs.js
│ ├── browser.es.js
│ ├── index.d.ts
│ ├── libratchet.browser.wasm
│ ├── libratchet.wasm
│ ├── libratchet.worker.wasm
│ ├── node.asmjs.cjs.js
│ ├── node.asmjs.es.js
│ ├── node.cjs.js
│ ├── node.es.js
│ ├── package.json
│ ├── worker.asmjs.cjs.js
│ ├── worker.asmjs.es.js
│ ├── worker.cjs.js
│ └── worker.es.js
├── crypto-types
│ ├── index.d.ts
│ └── package.json
├── data-utils
│ ├── package.json
│ ├── rollup.config.js
│ ├── src
│ │ ├── __tests__
│ │ │ ├── browser.test.ts
│ │ │ ├── dataToUint8Array.test.ts
│ │ │ ├── node.test.ts
│ │ │ └── toBuffer.test.ts
│ │ ├── browser.ts
│ │ ├── dataToUint8Array.ts
│ │ ├── node.ts
│ │ ├── toBuffer.ts
│ │ └── types.ts
│ └── tsconfig.json
├── init-utils
│ ├── package.json
│ ├── rollup.config.js
│ ├── src
│ │ ├── ModuleInitializer.ts
│ │ ├── __tests__
│ │ │ └── ModuleInitializer.test.ts
│ │ ├── errors.ts
│ │ └── index.ts
│ └── tsconfig.json
├── pythia-crypto
│ ├── browser.cjs.d.ts
│ ├── browser.cjs.js
│ ├── browser.es.d.ts
│ ├── browser.es.js
│ ├── package.json
│ ├── rollup.config.js
│ ├── src
│ │ ├── VirgilBrainKeyCrypto.ts
│ │ ├── VirgilPythiaCrypto.ts
│ │ ├── __tests__
│ │ │ ├── VirgilBrainKeyCrypto.test.ts
│ │ │ ├── VirgilPythiaCrypto.test.ts
│ │ │ ├── data.json
│ │ │ └── index.d.ts
│ │ ├── index.ts
│ │ ├── pythiaModules.ts
│ │ └── types.ts
│ ├── tsconfig.json
│ ├── workder.cjs.d.ts
│ ├── worker.cjs.js
│ ├── worker.es.d.ts
│ └── worker.es.js
├── sdk-crypto
│ ├── package.json
│ ├── rollup.config.js
│ ├── src
│ │ ├── VirgilAccessTokenSigner.ts
│ │ ├── VirgilCardCrypto.ts
│ │ ├── VirgilPrivateKeyExporter.ts
│ │ ├── index.ts
│ │ └── types.ts
│ └── tsconfig.json
└── virgil-crypto
│ ├── README.md
│ ├── browser.cjs.d.ts
│ ├── browser.cjs.js
│ ├── browser.es.d.ts
│ ├── browser.es.js
│ ├── package.json
│ ├── rollup.config.js
│ ├── src
│ ├── HashAlgorithm.ts
│ ├── KeyPairType.ts
│ ├── VirgilCrypto.ts
│ ├── VirgilCryptoError.ts
│ ├── VirgilPrivateKey.ts
│ ├── VirgilPublicKey.ts
│ ├── VirgilStreamCipher.ts
│ ├── VirgilStreamDecipher.ts
│ ├── VirgilStreamDecryptAndVerify.ts
│ ├── VirgilStreamSignAndEncrypt.ts
│ ├── VirgilStreamSigner.ts
│ ├── VirgilStreamVerifier.ts
│ ├── __tests__
│ │ ├── Crypto.test.ts
│ │ ├── CryptoCompatibility.test.ts
│ │ ├── CryptoFormats.test.ts
│ │ ├── VirgilCrypto.test.ts
│ │ ├── VirgilGroupSession.test.ts
│ │ ├── VirgilStreamCipher.test.ts
│ │ ├── VirgilStreamDecipher.test.ts
│ │ ├── VirgilStreamDecryptAndVerify.test.ts
│ │ ├── VirgilStreamSignAndEncrypt.test.ts
│ │ ├── VirgilStreamSigner.test.ts
│ │ ├── VirgilStreamVerifier.test.ts
│ │ ├── compatibility.test.ts
│ │ ├── crypto_compatibility_data.json
│ │ ├── testData.txt
│ │ └── validators.test.ts
│ ├── constants.ts
│ ├── foundationModules.ts
│ ├── globalInstances.ts
│ ├── groups
│ │ ├── createVirgilGroupSession.ts
│ │ └── helpers.ts
│ ├── index.ts
│ ├── types.ts
│ ├── utils.ts
│ └── validators.ts
│ ├── tsconfig.json
│ ├── worker.cjs.d.ts
│ ├── worker.cjs.js
│ ├── worker.es.d.ts
│ └── worker.es.js
├── utils
├── build.js
├── declaration.d.ts.template
└── rollup-common-configs.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | packages/*/dist
2 | packages/*/node_modules
3 | packages/core-foundation/*
4 | packages/core-phe/*
5 | packages/core-pythia/*
6 | packages/core-ratchet/*
7 | !packages/core-foundation/index.d.ts
8 | !packages/core-phe/index.d.ts
9 | !packages/core-pythia/index.d.ts
10 | !packages/core-ratchet/index.d.ts
11 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "es6": true,
5 | "node": true
6 | },
7 | "overrides": [
8 | {
9 | "files": "*.js",
10 | "extends": [
11 | "eslint:recommended",
12 | "prettier"
13 | ],
14 | "plugins": [
15 | "prettier"
16 | ],
17 | "parserOptions": {
18 | "ecmaVersion": 2019,
19 | "sourceType": "module"
20 | },
21 | "rules": {
22 | "prettier/prettier": "error"
23 | }
24 | },
25 | {
26 | "files": "*.ts",
27 | "parser": "@typescript-eslint/parser",
28 | "extends": [
29 | "eslint:recommended",
30 | "plugin:@typescript-eslint/eslint-recommended",
31 | "plugin:@typescript-eslint/recommended",
32 | "prettier/@typescript-eslint"
33 | ],
34 | "plugins": [
35 | "@typescript-eslint",
36 | "prettier"
37 | ],
38 | "rules": {
39 | "@typescript-eslint/explicit-function-return-type": "off",
40 | "@typescript-eslint/explicit-member-accessibility": "off",
41 | "prettier/prettier": "error"
42 | }
43 | }
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/.github/workflows/build-linux.yml:
--------------------------------------------------------------------------------
1 | name: Build on Linux
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node-version: ['18', '20', '21']
11 |
12 | name: Node.js ${{ matrix.node-version }}
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 | - name: Use Node.js ${{ matrix.node-version }}
17 | uses: actions/setup-node@v3
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 |
21 | - name: Install dependencies
22 | run: |
23 | yarn
24 | yarn prepare
25 |
26 | # - name: Run linter
27 | # run: yarn lint
28 |
29 | - name: Run tests
30 | run: yarn test
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .idea
4 | .vscode
5 |
6 | node_modules
7 | package-lock.json
8 | *.log
9 |
10 | .env
11 |
12 | .rpt2_cache
13 | dist
14 |
--------------------------------------------------------------------------------
/.huskyrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "hooks": {
3 | "pre-commit": "lint-staged"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,ts}": [
3 | "eslint --fix"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100,
3 | "tabWidth": 2,
4 | "singleQuote": true,
5 | "trailingComma": "all"
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015-2020, Virgil Security, Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of virgil nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | packages/virgil-crypto/README.md
--------------------------------------------------------------------------------
/benchmark/README.md:
--------------------------------------------------------------------------------
1 | # Benchmarks
2 |
3 | Results below were obtained on macOS Mojave with Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
4 |
5 | ## Node.js (Version: v10.15.3)
6 |
7 | ### generateKeys
8 | - v3 x 153 ops/sec ±2.47% (76 runs sampled)
9 | - v4 x 224 ops/sec ±2.99% (77 runs sampled)
10 |
11 | Fastest is v4
12 |
13 | ### generateKeysFromKeyMaterial
14 | - v3 x 157 ops/sec ±1.68% (78 runs sampled)
15 | - v4 x 244 ops/sec ±1.73% (82 runs sampled)
16 |
17 | Fastest is v4
18 |
19 | ### importPrivateKey
20 | - v3 x 247 ops/sec ±1.40% (83 runs sampled)
21 | - v4 x 10,187 ops/sec ±2.14% (87 runs sampled)
22 |
23 | Fastest is v4
24 |
25 | ### exportPrivateKey
26 | - v3 x 43,109,066 ops/sec ±8.58% (65 runs sampled)
27 | - v4 x 11,302 ops/sec ±2.02% (88 runs sampled)
28 |
29 | Fastest is v3
30 |
31 | ### importPublicKey
32 | - v3 x 508 ops/sec ±0.85% (90 runs sampled)
33 | - v4 x 138,722 ops/sec ±2.97% (83 runs sampled)
34 |
35 | Fastest is v4
36 |
37 | ### exportPublicKey
38 | - v3 x 106,722,197 ops/sec ±7.41% (68 runs sampled)
39 | - v4 x 5,837,392 ops/sec ±2.79% (90 runs sampled)
40 |
41 | Fastest is v3
42 |
43 | ### encrypt
44 | - v3 x 250 ops/sec ±0.35% (89 runs sampled)
45 | - v4 x 3,097 ops/sec ±0.76% (90 runs sampled)
46 |
47 | Fastest is v4
48 |
49 | ### decrypt
50 | - v3 x 236 ops/sec ±1.00% (84 runs sampled)
51 | - v4 x 2,885 ops/sec ±1.91% (88 runs sampled)
52 |
53 | Fastest is v4
54 |
55 | ### calculateHash
56 | - v3 x 21,490 ops/sec ±2.45% (84 runs sampled)
57 | - v4 x 183,644 ops/sec ±1.18% (91 runs sampled)
58 |
59 | Fastest is v4
60 |
61 | ### extractPublicKey
62 | - v3 x 498 ops/sec ±1.11% (88 runs sampled)
63 | - v4 x 10,963 ops/sec ±1.65% (84 runs sampled)
64 |
65 | Fastest is v4
66 |
67 | ### calculateSignature
68 | - v3 x 477 ops/sec ±1.35% (87 runs sampled)
69 | - v4 x 3,955 ops/sec ±0.74% (90 runs sampled)
70 |
71 | Fastest is v4
72 |
73 | ### verifySignature
74 | - v3 x 494 ops/sec ±0.57% (87 runs sampled)
75 | - v4 x 5,025 ops/sec ±0.84% (90 runs sampled)
76 |
77 | Fastest is v4
78 |
79 | ### signThenEncrypt
80 | - v3 x 148 ops/sec ±2.18% (74 runs sampled)
81 | - v4 x 1,669 ops/sec ±1.89% (89 runs sampled)
82 |
83 | Fastest is v4
84 |
85 | ### decryptThenVerify
86 | - v3 x 164 ops/sec ±1.58% (82 runs sampled)
87 | - v4 x 1,833 ops/sec ±2.50% (86 runs sampled)
88 |
89 | Fastest is v4
90 |
91 | ### getRandomBytes
92 | - v3 x 482 ops/sec ±2.17% (85 runs sampled)
93 | - v4 x 290,611 ops/sec ±3.66% (81 runs sampled)
94 |
95 | Fastest is v4
96 |
97 | ### signThenEncryptDetached
98 | - v3 x 165 ops/sec ±0.56% (82 runs sampled)
99 | - v4 x 1,734 ops/sec ±0.69% (91 runs sampled)
100 |
101 | Fastest is v4
102 |
103 | ### decryptThenVerifyDetached
104 | - v3 x 157 ops/sec ±1.00% (78 runs sampled)
105 | - v4 x 1,843 ops/sec ±1.44% (86 runs sampled)
106 |
107 | Fastest is v4
108 |
109 | ### Group Encryption (v4 only)
110 | - encrypt x 3,173 ops/sec ±1.88% (84 runs sampled)
111 |
112 | ### Group Decryption (v4 only)
113 | - decrypt x 4,496 ops/sec ±0.51% (93 runs sampled)
114 |
115 | ## Browser (chrome/78.0.3882)
116 |
117 | ### generateKeys
118 | - v3 x 54.45 ops/sec ±2.55% (47 runs sampled)
119 | - v4 x 265 ops/sec ±0.44% (62 runs sampled)
120 |
121 | Fastest is v4
122 |
123 | ### generateKeysFromKeyMaterial
124 | - v3 x 70.79 ops/sec ±0.54% (53 runs sampled)
125 | - v4 x 258 ops/sec ±1.00% (60 runs sampled)
126 |
127 | Fastest is v4
128 |
129 | ### importPrivateKey
130 | - v3 x 94.46 ops/sec ±1.17% (55 runs sampled)
131 | - v4 x 13,254 ops/sec ±1.88% (60 runs sampled)
132 |
133 | Fastest is v4
134 |
135 | ### exportPrivateKey
136 | - v3 x 73,357,171 ops/sec ±0.54% (64 runs sampled)
137 | - v4 x 13,616 ops/sec ±0.86% (63 runs sampled)
138 |
139 | Fastest is v3
140 |
141 | ### importPublicKey
142 | - v3 x 231 ops/sec ±0.81% (60 runs sampled)
143 | - v4 x 181,675 ops/sec ±1.02% (62 runs sampled)
144 |
145 | Fastest is v4
146 |
147 | ### exportPublicKey
148 | - v3 x 815,835,828 ops/sec ±0.72% (65 runs sampled)
149 | - v4 x 1,324,772 ops/sec ±0.45% (66 runs sampled)
150 |
151 | Fastest is v3
152 |
153 | ### encrypt
154 | - v3 x 76.34 ops/sec ±0.78% (57 runs sampled)
155 | - v4 x 3,239 ops/sec ±1.23% (21 runs sampled)
156 |
157 | Fastest is v4
158 |
159 | ### decrypt
160 | - v3 x 77.17 ops/sec ±1.61% (53 runs sampled)
161 | - v4 x 3,674 ops/sec ±0.46% (64 runs sampled)
162 |
163 | Fastest is v4
164 |
165 | ### calculateHash
166 | - v3 x 4,373 ops/sec ±0.96% (26 runs sampled)
167 | - v4 x 159,126 ops/sec ±1.87% (59 runs sampled)
168 |
169 | Fastest is v4
170 |
171 | ### extractPublicKey
172 | - v3 x 189 ops/sec ±2.58% (60 runs sampled)
173 | - v4 x 14,536 ops/sec ±0.46% (65 runs sampled)
174 |
175 | Fastest is v4
176 |
177 | ### calculateSignature
178 | - v3 x 142 ops/sec ±0.85% (56 runs sampled)
179 | - v4 x 4,216 ops/sec ±1.29% (61 runs sampled)
180 |
181 | Fastest is v4
182 |
183 | ### verifySignature
184 | - v3 x 116 ops/sec ±1.86% (58 runs sampled)
185 | - v4 x 6,167 ops/sec ±0.87% (35 runs sampled)
186 |
187 | Fastest is v4
188 |
189 | ### signThenEncrypt
190 | - v3 x 48.47 ops/sec ±0.74% (51 runs sampled)
191 | - v4 x 1,835 ops/sec ±2.11% (14 runs sampled)
192 |
193 | Fastest is v4
194 |
195 | ### decryptThenVerify
196 | - v3 x 40.92 ops/sec ±1.59% (44 runs sampled)
197 | - v4 x 2,204 ops/sec ±1.31% (64 runs sampled)
198 |
199 | Fastest is v4
200 |
201 | ### getRandomBytes
202 | - v3 x 247 ops/sec ±0.99% (61 runs sampled)
203 | - v4 x 290,023 ops/sec ±1.52% (61 runs sampled)
204 |
205 | Fastest is v4
206 |
207 | ### signThenEncryptDetached
208 | - v3 x 43.18 ops/sec ±2.82% (46 runs sampled)
209 | - v4 x 1,866 ops/sec ±2.37% (58 runs sampled)
210 |
211 | Fastest is v4
212 |
213 | ### decryptThenVerifyDetached
214 | - v3 x 47.78 ops/sec ±2.14% (51 runs sampled)
215 | - v4 x 2,202 ops/sec ±0.85% (63 runs sampled)
216 |
217 | Fastest is v4
218 |
219 | ### Group Encryption (v4 only)
220 | - encrypt x 4,006 ops/sec ±1.47% (25 runs sampled)
221 |
222 | ### Group Decryption (v4 only)
223 | - decrypt x 4,705 ops/sec ±4.67% (28 runs sampled)
224 |
--------------------------------------------------------------------------------
/benchmark/browser.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 |
3 | require('core-js/stable');
4 | require('regenerator-runtime/runtime');
5 |
6 | const runBenchmark = require('./benchmark');
7 | const { detect } = require('detect-browser');
8 |
9 | (async () => {
10 | const browser = detect();
11 | const lines = [`## Browser (${browser.name}/${browser.version})\n`];
12 | await runBenchmark(window.Benchmark, str => lines.push(str));
13 | await fetch('/lines', {
14 | method: 'POST',
15 | headers: {
16 | 'Content-Type': 'application/json',
17 | },
18 | body: JSON.stringify({ lines }),
19 | });
20 | const doneElement = document.createElement('div');
21 | doneElement.id = 'done';
22 | document.body.appendChild(doneElement);
23 | })();
24 |
--------------------------------------------------------------------------------
/benchmark/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Virgil Crypto JavaScript Benchmark
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/benchmark/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const http = require('http');
3 | const path = require('path');
4 | const os = require('os');
5 | const osName = require('os-name');
6 |
7 | const benchmark = require('benchmark');
8 | const puppeteer = require('puppeteer');
9 | const serveHandler = require('serve-handler');
10 | const webpack = require('webpack');
11 |
12 | const runBenchmark = require('./benchmark');
13 | const webpackConfig = require('./webpack.config');
14 |
15 | const SERVER_PORT = 3000;
16 | const OUTPUT_FILE_PATH = path.join(__dirname, 'README.md');
17 |
18 | const getSystemInfo = () =>
19 | `\nResults below were obtained on ${osName()} with ${os.cpus()[0].model}\n`;
20 |
21 | const runNodeBenchmark = async () => {
22 | const lines = [`## Node.js (Version: ${process.version})\n`];
23 | await runBenchmark(benchmark, str => lines.push(str));
24 | return lines;
25 | };
26 |
27 | const runBrowserBenchmark = async () => {
28 | const browser = await puppeteer.launch();
29 | return new Promise(resolve => {
30 | const server = http.createServer((request, response) => {
31 | if (request.method === 'POST' && request.url === '/lines') {
32 | let body = '';
33 | request.on('data', chunk => {
34 | body += chunk;
35 | });
36 | request.on('end', () => {
37 | response.end();
38 | server.close(async () => {
39 | await browser.close();
40 | resolve(JSON.parse(body).lines);
41 | });
42 | });
43 | } else {
44 | serveHandler(request, response, {
45 | public: webpackConfig.output.path,
46 | directoryListing: false,
47 | headers: [
48 | {
49 | source: '*.wasm',
50 | headers: [{ key: 'Content-Type', value: 'application/wasm' }],
51 | },
52 | ],
53 | });
54 | }
55 | });
56 | webpack(webpackConfig, () => {
57 | server.listen(SERVER_PORT, async () => {
58 | const page = await browser.newPage();
59 | await page.goto(`http://localhost:${SERVER_PORT}`);
60 | await page.waitForSelector('#done', { timeout: 0 });
61 | });
62 | });
63 | });
64 | };
65 |
66 | (async () => {
67 | console.log('Running benchmarks. This process can take several minutes. Please wait...');
68 | const [nodejsLines, browserLines] = await Promise.all([
69 | runNodeBenchmark(),
70 | runBrowserBenchmark(),
71 | ]);
72 | const lines = ['# Benchmarks', getSystemInfo(), ...nodejsLines, ...browserLines];
73 | fs.writeFileSync(OUTPUT_FILE_PATH, lines.join('\n'));
74 | console.log(`${OUTPUT_FILE_PATH} was created`);
75 | })();
76 |
--------------------------------------------------------------------------------
/benchmark/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/benchmark",
3 | "version": "1.0.0",
4 | "description": "Virgil JavaScript Crypto library benchmarks",
5 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/benchmark",
6 | "author": "Virgil Security Inc. ",
7 | "license": "BSD-3-Clause",
8 | "private": true,
9 | "scripts": {
10 | "benchmarks": "node index.js",
11 | "clean": "rimraf dist README.md",
12 | "start": "npm run clean && npm run benchmarks"
13 | },
14 | "dependencies": {
15 | "@babel/core": "^7.5.5",
16 | "@babel/preset-env": "^7.5.5",
17 | "babel-loader": "^8.0.6",
18 | "benchmark": "^2.1.4",
19 | "buffer": "^5.2.1",
20 | "core-js": "^3.2.1",
21 | "detect-browser": "^4.7.0",
22 | "file-loader": "^4.1.0",
23 | "html-webpack-plugin": "^5.5.1",
24 | "os-name": "^3.1.0",
25 | "puppeteer": "^1.20.0",
26 | "regenerator-runtime": "^0.13.3",
27 | "serve-handler": "^6.1.1",
28 | "virgil-crypto": "^4.0.0-alpha.17",
29 | "virgil-crypto-3": "npm:virgil-crypto@^3.2.6",
30 | "webpack": "^4.37.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/benchmark/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | module.exports = {
6 | mode: 'production',
7 | entry: path.join(__dirname, 'browser.js'),
8 | output: {
9 | path: path.join(__dirname, 'dist'),
10 | filename: '[name].[hash].js',
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.js$/,
16 | exclude: /node_modules/,
17 | loader: 'babel-loader',
18 | options: {
19 | presets: ['@babel/preset-env'],
20 | },
21 | },
22 | {
23 | test: /\.wasm$/,
24 | type: 'javascript/auto',
25 | loader: 'file-loader',
26 | options: {
27 | name: '[name].[ext]',
28 | },
29 | },
30 | ],
31 | },
32 | plugins: [new HtmlWebpackPlugin({ template: path.join(__dirname, 'index.html') })],
33 | };
34 |
--------------------------------------------------------------------------------
/examples/webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/example-webpack",
3 | "version": "1.0.0",
4 | "description": "Webpack demo",
5 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/examples/webpack",
6 | "author": "Virgil Security Inc. ",
7 | "license": "BSD-3-Clause",
8 | "private": true,
9 | "scripts": {
10 | "start": "webpack-dev-server",
11 | "build": "webpack"
12 | },
13 | "dependencies": {
14 | "mocha": "^10.2.0",
15 | "virgil-crypto": "^5.1.0"
16 | },
17 | "devDependencies": {
18 | "file-loader": "^6.2.0",
19 | "html-webpack-plugin": "^5.5.1",
20 | "webpack": "^5.89.0",
21 | "webpack-cli": "^5.1.4",
22 | "webpack-dev-server": "^4.13.3"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/webpack/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Webpack demo
8 |
9 |
10 | Check dev tools
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/webpack/src/index.js:
--------------------------------------------------------------------------------
1 | import { initCrypto, VirgilCrypto } from 'virgil-crypto';
2 |
3 | initCrypto().then(() => {
4 | const virgilCrypto = new VirgilCrypto();
5 | const keys = virgilCrypto.generateKeys();
6 | const data = 'data';
7 | const encrypted = virgilCrypto.encrypt({ value: data, encoding: 'utf8' }, keys.publicKey);
8 | const decrypted = virgilCrypto.decrypt(encrypted, keys.privateKey);
9 | console.log(data);
10 | console.log(decrypted.toString());
11 | });
12 |
--------------------------------------------------------------------------------
/examples/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | const sourceRoot = path.join(__dirname, 'src');
6 |
7 | module.exports = {
8 | mode: 'development',
9 | entry: path.join(sourceRoot, 'index.js'),
10 | module: {
11 | rules: [
12 | {
13 | test: /\.wasm$/,
14 | type: 'javascript/auto',
15 | loader: 'file-loader',
16 | },
17 | ],
18 | },
19 | plugins: [new HtmlWebpackPlugin({ template: path.join(sourceRoot, 'index.html') })],
20 | };
21 |
--------------------------------------------------------------------------------
/guides/create-react-app.md:
--------------------------------------------------------------------------------
1 | # Virgil Security JavaScript Crypto Library - Create React App
2 | You need an ability to tweak [create-react-app](https://github.com/facebook/create-react-app) configs. You have 2 options here:
3 | - Override options using [react-app-rewired](https://github.com/timarney/react-app-rewired) or its alternatives.
4 | - [Eject](https://facebook.github.io/create-react-app/docs/available-scripts#npm-run-eject). Please note that this is a one-way operation.
5 |
6 | ## react-app-rewired
7 | Add the following to your `config-overrides.js`:
8 | ```js
9 | const path = require('path');
10 | module.exports = (config, env) => {
11 | // Use file-loader to copy WebAssembly files
12 | // https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/config/webpack.config.js#L378
13 | config.module.rules[2].oneOf.unshift({
14 | test: /\.wasm$/,
15 | type: 'javascript/auto',
16 | loader: 'file-loader',
17 | });
18 | return config;
19 | };
20 | ```
21 |
22 | ## Eject
23 | Follow our [Webpack guide](webpack.md).
24 |
25 | ## Support
26 | Our developer support team is here to help you.
27 |
28 | You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com.
29 |
30 | Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community).
31 |
--------------------------------------------------------------------------------
/guides/react-native.md:
--------------------------------------------------------------------------------
1 | # Virgil Security JavaScript Crypto Library - React Native
2 | We created a [native module for React Native](https://github.com/VirgilSecurity/react-native-virgil-crypto).
3 |
4 | This library's API is compatible with the [virgil-crypto for JavaScript](https://github.com/VirgilSecurity/virgil-crypto-javascript) and can be used in place of the latter in React Native projects. The main difference is that in JS library a class named `VirgilCrypto` is exported from the module that you need to create instances of, whereas this library exports an "instance" of that class ready to be used. Also, stream encryption is not available as there is no stream implementation in React Native. We're investigating the options to support file encryption though.
5 |
6 | ## Support
7 | Our developer support team is here to help you.
8 |
9 | You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com.
10 |
11 | Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community).
12 |
--------------------------------------------------------------------------------
/guides/umd.md:
--------------------------------------------------------------------------------
1 | # Virgil Security JavaScript Crypto Library - UMD module
2 | First, you need to add a `
6 | ```
7 | - asm.js. Use it only in case you need to support old web browsers.
8 | ```html
9 |
10 | ```
11 |
12 | And then simply use the library:
13 | ```js
14 | // Use the global variable `VirgilCrypto` as a namespace object,
15 | // containing all of module exports as properties
16 | VirgilCrypto.initCrypto().then(() => {
17 | const virgilCrypto = new VirgilCrypto.VirgilCrypto();
18 | // ... your code here ...
19 | });
20 | ```
21 |
22 | Also make sure to get familiar with [usage examples](usage-examples.md) of the library.
23 |
24 | ## Support
25 | Our developer support team is here to help you.
26 |
27 | You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com.
28 |
29 | Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community).
30 |
--------------------------------------------------------------------------------
/guides/usage-examples.md:
--------------------------------------------------------------------------------
1 | # Virgil Security JavaScript Crypto Library - Usage Examples
2 |
3 | ## Generate a key pair
4 | Generate a Private Key with the default algorithm (ED25519):
5 | ```js
6 | import { initCrypto, VirgilCrypto } from 'virgil-crypto';
7 | // You may replace this import with an import that suits your environment
8 |
9 | initCrypto().then(() => {
10 | const virgilCrypto = new VirgilCrypto();
11 | const keyPair = virgilCrypto.generateKeys();
12 | });
13 | ```
14 |
15 | ## Generate and verify a signature
16 | Generate signature and sign data with a private key:
17 | ```js
18 | import { initCrypto, VirgilCrypto } from 'virgil-crypto';
19 | // You may replace this import with an import that suits your environment
20 |
21 | initCrypto().then(() => {
22 | const virgilCrypto = new VirgilCrypto();
23 | const signingKeypair = virgilCrypto.generateKeys();
24 |
25 | // prepare a message
26 | const messageToSign = 'Hello, Bob!';
27 |
28 | // generate a signature
29 | const signature = virgilCrypto.calculateSignature(
30 | { value: messageToSign, encoding: 'utf8' },
31 | signingKeypair.privateKey
32 | );
33 | // signature is a NodeJS Buffer (or polyfill if in the browser)
34 | console.log(signature.toString('base64'));
35 | });
36 | ```
37 |
38 | Verify a signature with a public key:
39 | ```js
40 | // verify a signature
41 | const verified = virgilCrypto.verifySignature(
42 | { value: messageToSign, encoding: 'utf8' },
43 | signature,
44 | signingKeypair.publicKey
45 | );
46 | ```
47 |
48 | ## Encrypt and decrypt data
49 | Encrypt Data on a Public Key:
50 | ```js
51 | import { initCrypto, VirgilCrypto } from 'virgil-crypto';
52 | // You may replace this import with an import that suits your environment
53 |
54 | initCrypto().then(() => {
55 | const virgilCrypto = new VirgilCrypto();
56 | const encryptionKeypair = virgilCrypto.generateKeys();
57 |
58 | // prepare a message
59 | const messageToEncrypt = 'Hello, Bob!';
60 |
61 | // generate a signature
62 | const encryptedData = virgilCrypto.encrypt(
63 | { value: messageToEncrypt, encoding: 'utf8' },
64 | encryptionKeypair.publicKey
65 | );
66 | // encryptedData is a NodeJS Buffer (or polyfill if in the browser)
67 | console.log(encryptedData.toString('base64'));
68 | });
69 | ```
70 |
71 | Decrypt the encrypted data with a Private Key:
72 | ```js
73 | // decrypt the encrypted data using a private key
74 | const decryptedData = virgilCrypto.decrypt(encryptedData, encryptionKeypair.privateKey);
75 |
76 | // convert Buffer to string
77 | const decryptedMessage = decryptedData.toString('utf8');
78 | ```
79 |
80 | ## Support
81 | Our developer support team is here to help you.
82 |
83 | You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com.
84 |
85 | Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community).
86 |
--------------------------------------------------------------------------------
/guides/webpack.md:
--------------------------------------------------------------------------------
1 | # Virgil Security JavaScript Crypto Library - Webpack
2 | Select approach you have decided to use:
3 | - [WebAssembly](#webassembly)
4 | - [asm.js](#asmjs)
5 |
6 | ## WebAssembly
7 | First, you need to install [file-loader](https://github.com/webpack-contrib/file-loader) if you haven't used it yet:
8 | ```sh
9 | npm install file-loader --save-dev
10 | ```
11 |
12 | Second, you need to add a [rule](https://webpack.js.org/configuration/module/#rule) to copy WebAssembly file:
13 | ```js
14 | {
15 | test: /\.wasm$/,
16 | type: 'javascript/auto',
17 | loader: 'file-loader',
18 | }
19 | ```
20 |
21 | Last, you need to import the library:
22 | ```js
23 | import { initCrypto, VirgilCrypto } 'virgil-crypto';
24 | ```
25 |
26 | Here is [complete working demo](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/examples/webpack) of this approach.
27 |
28 | ## asm.js
29 | First, you need to [disable mocking of Node.js modules and globals](https://webpack.js.org/configuration/node) in your Webpack config:
30 | ```js
31 | node: false
32 | ```
33 |
34 | And then simply import the library:
35 | ```js
36 | import { initCrypto, VirgilCrypto } from 'virgil-crypto/dist/browser.asmjs.es';
37 | ```
38 |
39 | ## Support
40 | Our developer support team is here to help you.
41 |
42 | You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com.
43 |
44 | Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community).
45 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "npmClient": "yarn",
3 | "packages": [
4 | "packages/*"
5 | ],
6 | "version": "independent"
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "root",
3 | "private": true,
4 | "scripts": {
5 | "test": "lerna run test --stream",
6 | "lint": "eslint '**/*.{js,ts}'",
7 | "prepare": "lerna run prepare --stream"
8 | },
9 | "devDependencies": {
10 | "@typescript-eslint/eslint-plugin": "^6.16.0",
11 | "@typescript-eslint/parser": "^6.16.0",
12 | "eslint": "^8.56.0",
13 | "eslint-config-prettier": "^9.1.0",
14 | "eslint-plugin-prettier": "^5.1.2",
15 | "husky": "^8.0.3",
16 | "lerna": "^8.0.1",
17 | "lerna-update-wizard": "^1.1.2",
18 | "lint-staged": "^15.2.0",
19 | "prettier": "3.1.1",
20 | "rollup-plugin-copy": "^3.2.1",
21 | "rollup-plugin-typescript2": "^0.36.0",
22 | "ts-node": "^10.9.2",
23 | "typescript": "5.3.3"
24 | },
25 | "workspaces": [
26 | "benchmark",
27 | "examples/*",
28 | "packages/*"
29 | ],
30 | "dependencies": {
31 | "html-webpack-plugin": "5.6.0",
32 | "mocha": "10.2.0",
33 | "webpack-dev-server": "4.15.1"
34 | },
35 | "resolutions": {
36 | "glob-parent": "^6.0.1"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/core-foundation/libfoundation.browser.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-foundation/libfoundation.browser.wasm
--------------------------------------------------------------------------------
/packages/core-foundation/libfoundation.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-foundation/libfoundation.wasm
--------------------------------------------------------------------------------
/packages/core-foundation/libfoundation.worker.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-foundation/libfoundation.worker.wasm
--------------------------------------------------------------------------------
/packages/core-foundation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/core-foundation",
3 | "version": "2.1.0",
4 | "description": "Virgil Foundation",
5 | "main": "./node.cjs.js",
6 | "module": "./node.es.js",
7 | "browser": {
8 | "./node.cjs.js": "./browser.cjs.js",
9 | "./node.es.js": "./browser.es.js"
10 | },
11 | "typings": "./index.d.ts",
12 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/core-foundation",
13 | "author": "Virgil Security Inc. ",
14 | "license": "BSD-3-Clause",
15 | "publishConfig": {
16 | "access": "public"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/core-phe/index.d.ts:
--------------------------------------------------------------------------------
1 | declare namespace PheModules {
2 | export class PheObject {
3 | delete(): void;
4 | }
5 |
6 | export interface Random {
7 | random(dataLen: number): Uint8Array;
8 | reseed(): void;
9 | }
10 |
11 | export interface Hash {
12 | DIGEST_LEN: number;
13 | BLOCK_LEN: number;
14 | hash(data: Uint8Array): Uint8Array;
15 | start(): void;
16 | update(data: Uint8Array): void;
17 | finish(): Uint8Array;
18 | }
19 |
20 | export interface Kdf {
21 | derive(data: Uint8Array, keyLen: number): Uint8Array;
22 | }
23 |
24 | export interface SaltedKdf {
25 | reset(salt: Uint8Array, iterationCount: number): void;
26 | setInfo(info: Uint8Array): void;
27 | }
28 |
29 | export interface Mac {
30 | digestLen(): number;
31 | mac(key: Uint8Array, data: Uint8Array): Uint8Array;
32 | start(key: Uint8Array): void;
33 | update(data: Uint8Array): void;
34 | finish(): Uint8Array;
35 | reset(): void;
36 | }
37 |
38 | export class PheCipher extends PheObject {
39 | random: Random;
40 | setupDefaults(): void;
41 | encryptLen(plainTextLen: number): number;
42 | decryptLen(cipherTextLen: number): number;
43 | encrypt(plainText: Uint8Array, accountKey: Uint8Array): Uint8Array;
44 | decrypt(cipherText: Uint8Array, accountKey: Uint8Array): Uint8Array;
45 | authEncrypt(
46 | plainText: Uint8Array,
47 | additionalData: Uint8Array,
48 | accountKey: Uint8Array,
49 | ): Uint8Array;
50 | authDecrypt(
51 | cipherText: Uint8Array,
52 | additionalData: Uint8Array,
53 | accountKey: Uint8Array,
54 | ): Uint8Array;
55 | }
56 |
57 | export class PheClient extends PheObject {
58 | random: Random;
59 | operationRandom: Random;
60 | setupDefaults(): void;
61 | setKeys(clientPrivateKey: Uint8Array, serverPublicKey: Uint8Array): void;
62 | generateClientPrivateKey(): Uint8Array;
63 | enrollmentRecordLen(): number;
64 | enrollAccount(
65 | enrollmentResponse: Uint8Array,
66 | password: Uint8Array,
67 | ): { enrollmentRecord: Uint8Array; accountKey: Uint8Array };
68 | verifyPasswordRequestLen(): number;
69 | createVerifyPasswordRequest(password: Uint8Array, enrollmentRecord: Uint8Array): Uint8Array;
70 | checkResponseAndDecrypt(
71 | password: Uint8Array,
72 | enrollmentRecord: Uint8Array,
73 | verifyPasswordResponse: Uint8Array,
74 | ): Uint8Array;
75 | rotateKeys(
76 | updateToken: Uint8Array,
77 | ): { newClientPrivateKey: Uint8Array; newServerPublicKey: Uint8Array };
78 | updateEnrollmentRecord(enrollmentRecord: Uint8Array, updateToken: Uint8Array): Uint8Array;
79 | }
80 |
81 | export class PheServer extends PheObject {
82 | random: Random;
83 | operationRandom: Random;
84 | setupDefaults(): void;
85 | generateServerKeyPair(): { serverPrivateKey: Uint8Array; serverPublicKey: Uint8Array };
86 | generateServerKeyPair(): number;
87 | getEnrollment(serverPrivateKey: Uint8Array, serverPublicKey: Uint8Array): Uint8Array;
88 | verifyPasswordResponseLen(): number;
89 | verifyPassword(
90 | serverPrivateKey: Uint8Array,
91 | serverPublicKey: Uint8Array,
92 | verifyPasswordRequest: Uint8Array,
93 | ): Uint8Array;
94 | updateTokenLen(): number;
95 | rotateKeys(
96 | serverPrivateKey: Uint8Array,
97 | ): { newServerPrivateKey: Uint8Array; newServerPublicKey: Uint8Array; updateToken: Uint8Array };
98 | }
99 |
100 | export class UokmsClient extends PheObject {
101 | random: Random;
102 | operationRandom: Random;
103 | setupDefaults(): void;
104 | setKeysOneparty(clientPrivateKey: Uint8Array): void;
105 | setKeys(clientPrivateKey: Uint8Array, serverPublicKey: Uint8Array): void;
106 | generateClientPrivateKey(): Uint8Array;
107 | generateEncryptWrap(encryptionKeyLen: number): { wrap: Uint8Array; encryptionKey: Uint8Array };
108 | decryptOneparty(wrap: Uint8Array, encryptionKeyLen: number): Uint8Array;
109 | generateDecryptRequest(
110 | wrap: Uint8Array,
111 | ): { deblindFactor: Uint8Array; decryptRequest: Uint8Array };
112 | processDecryptResponse(
113 | wrap: Uint8Array,
114 | decryptRequest: Uint8Array,
115 | decryptResponse: Uint8Array,
116 | deblindFactor: Uint8Array,
117 | encryptionKeyLen: number,
118 | ): Uint8Array;
119 | rotateKeysOneparty(updateToken: Uint8Array): Uint8Array;
120 | generateUpdateTokenOneparty(): Uint8Array;
121 | rotateKeys(
122 | updateToken: Uint8Array,
123 | ): { newClientPrivateKey: Uint8Array; newServerPublicKey: Uint8Array };
124 | }
125 |
126 | export class UokmsServer extends PheObject {
127 | random: Random;
128 | operationRandom: Random;
129 | setupDefaults(): void;
130 | generateServerKeyPair(): { serverPrivateKey: Uint8Array; serverPublicKey: Uint8Array };
131 | decryptResponseLen(): number;
132 | processDecryptRequest(serverPrivateKey: Uint8Array, decryptRequest: Uint8Array): Uint8Array;
133 | rotateKeys(
134 | serverPrivateKey: Uint8Array,
135 | ): { newServerPrivateKey: Uint8Array; newServerPublicKey: Uint8Array; updateToken: Uint8Array };
136 | }
137 |
138 | export class UokmsWrapRotation extends PheObject {
139 | operationRandom: Random;
140 | setupDefaults(): void;
141 | setUpdateToken(updateToken: Uint8Array): void;
142 | updateWrap(wrap: Uint8Array): Uint8Array;
143 | }
144 |
145 | export class CtrDrbg extends PheObject implements Random {
146 | RESEED_INTERVAL: number;
147 | ENTROPY_LEN: number;
148 | random(dataLen: number): Uint8Array;
149 | reseed(): void;
150 | setupDefaults(): void;
151 | enablePredictionResistance(): void;
152 | setReseedInterval(interval: number): void;
153 | setReseedInterval(len: number): void;
154 | }
155 |
156 | export class Hkdf extends PheObject implements Kdf, SaltedKdf {
157 | hash: Hash;
158 | derive(data: Uint8Array, keyLen: number): Uint8Array;
159 | reset(salt: Uint8Array, iterationCount: number): void;
160 | setInfo(info: Uint8Array): void;
161 | }
162 |
163 | export class Hmac extends PheObject implements Mac {
164 | hash: Hash;
165 | digestLen(): number;
166 | mac(key: Uint8Array, data: Uint8Array): Uint8Array;
167 | start(key: Uint8Array): void;
168 | update(data: Uint8Array): void;
169 | finish(): Uint8Array;
170 | reset(): void;
171 | }
172 |
173 | export class Sha512 extends PheObject implements Hash {
174 | DIGEST_LEN: number;
175 | BLOCK_LEN: number;
176 | hash(data: Uint8Array): Uint8Array;
177 | start(): void;
178 | update(data: Uint8Array): void;
179 | finish(): Uint8Array;
180 | }
181 | }
182 |
183 | declare module '@virgilsecurity/core-phe' {
184 | function initPhe(): Promise;
185 | export default initPhe;
186 | }
187 |
188 | declare module '@virgilsecurity/core-phe/*' {
189 | function initPhe(): Promise;
190 | export default initPhe;
191 | }
192 |
--------------------------------------------------------------------------------
/packages/core-phe/libphe.browser.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-phe/libphe.browser.wasm
--------------------------------------------------------------------------------
/packages/core-phe/libphe.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-phe/libphe.wasm
--------------------------------------------------------------------------------
/packages/core-phe/libphe.worker.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-phe/libphe.worker.wasm
--------------------------------------------------------------------------------
/packages/core-phe/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/core-phe",
3 | "version": "2.1.0",
4 | "description": "Virgil PHE",
5 | "main": "./node.cjs.js",
6 | "module": "./node.es.js",
7 | "browser": {
8 | "./node.cjs.js": "./browser.cjs.js",
9 | "./node.es.js": "./browser.es.js"
10 | },
11 | "typings": "./index.d.ts",
12 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/core-phe",
13 | "author": "Virgil Security Inc. ",
14 | "license": "BSD-3-Clause",
15 | "publishConfig": {
16 | "access": "public"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/core-pythia/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@virgilsecurity/core-pythia' {
2 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
3 | export type PythiaModules = any;
4 | function initRatchet(): Promise;
5 | export default initPythia;
6 | }
7 |
8 | declare module '@virgilsecurity/core-pythia/*' {
9 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 | export type PythiaModules = any;
11 | function initPythia(): Promise;
12 | export default initPythia;
13 | }
14 |
--------------------------------------------------------------------------------
/packages/core-pythia/libpythia.browser.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-pythia/libpythia.browser.wasm
--------------------------------------------------------------------------------
/packages/core-pythia/libpythia.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-pythia/libpythia.wasm
--------------------------------------------------------------------------------
/packages/core-pythia/libpythia.worker.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-pythia/libpythia.worker.wasm
--------------------------------------------------------------------------------
/packages/core-pythia/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/core-pythia",
3 | "version": "2.1.0",
4 | "description": "Virgil Pythia",
5 | "main": "./node.cjs.js",
6 | "module": "./node.es.js",
7 | "browser": {
8 | "./node.cjs.js": "./browser.cjs.js",
9 | "./node.es.js": "./browser.es.js"
10 | },
11 | "typings": "./index.d.ts",
12 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/core-pythia",
13 | "author": "Virgil Security Inc. ",
14 | "license": "BSD-3-Clause",
15 | "publishConfig": {
16 | "access": "public"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/core-ratchet/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@virgilsecurity/core-ratchet' {
2 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
3 | export type RatchetModules = any;
4 | function initRatchet(): Promise;
5 | export default initRatchet;
6 | }
7 |
8 | declare module '@virgilsecurity/core-ratchet/*' {
9 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 | export type RatchetModules = any;
11 | function initRatchet(): Promise;
12 | export default initRatchet;
13 | }
14 |
--------------------------------------------------------------------------------
/packages/core-ratchet/libratchet.browser.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-ratchet/libratchet.browser.wasm
--------------------------------------------------------------------------------
/packages/core-ratchet/libratchet.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-ratchet/libratchet.wasm
--------------------------------------------------------------------------------
/packages/core-ratchet/libratchet.worker.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-crypto-javascript/2f743d81319fdc23392e3707cd6cf826e1267eb6/packages/core-ratchet/libratchet.worker.wasm
--------------------------------------------------------------------------------
/packages/core-ratchet/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/core-ratchet",
3 | "version": "2.1.0",
4 | "description": "Virgil Ratchet",
5 | "main": "./node.cjs.js",
6 | "module": "./node.es.js",
7 | "browser": {
8 | "./node.cjs.js": "./browser.cjs.js",
9 | "./node.es.js": "./browser.es.js"
10 | },
11 | "typings": "./index.d.ts",
12 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/core-ratchet",
13 | "author": "Virgil Security Inc. ",
14 | "license": "BSD-3-Clause",
15 | "publishConfig": {
16 | "access": "public"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/crypto-types/index.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/interface-name-prefix */
2 |
3 | ///
4 |
5 | export type StringEncoding = BufferEncoding;
6 |
7 | export type NodeBuffer = Buffer;
8 |
9 | export interface StringWithEncoding {
10 | value: string;
11 | encoding: StringEncoding;
12 | }
13 |
14 | export type Data = NodeBuffer | Uint8Array | StringWithEncoding | string;
15 |
16 | export interface IPrivateKey {
17 | identifier: NodeBuffer;
18 | }
19 |
20 | export interface IPublicKey {
21 | identifier: NodeBuffer;
22 | }
23 |
24 | export interface IKeyPair {
25 | privateKey: IPrivateKey;
26 | publicKey: IPublicKey;
27 | }
28 |
29 | export interface IGroupSessionMessageInfo {
30 | sessionId: string;
31 | epochNumber: number;
32 | data: string;
33 | }
34 |
35 | export interface IGroupSession {
36 | getSessionId(): string;
37 | getCurrentEpochNumber(): number;
38 | encrypt(data: Data, signingPrivateKey: IPrivateKey): NodeBuffer;
39 | decrypt(encryptedData: Data, verifyingPublicKey: IPublicKey): NodeBuffer;
40 | addNewEpoch(): IGroupSessionMessageInfo;
41 | export(): NodeBuffer[];
42 | parseMessage(messageData: Data): IGroupSessionMessageInfo;
43 | }
44 |
45 | export interface ICrypto {
46 | generateKeys(keyPairType?: unknown): IKeyPair;
47 | generateKeysFromKeyMaterial(keyMaterial: Data, keyPairType?: unknown): IKeyPair;
48 | importPrivateKey(rawPrivateKey: Data): IPrivateKey;
49 | exportPrivateKey(privateKey: IPrivateKey): NodeBuffer;
50 | importPublicKey(rawPublicKey: Data): IPublicKey;
51 | exportPublicKey(publicKey: IPublicKey): NodeBuffer;
52 | encrypt(data: Data, publicKey: IPublicKey, enablePadding?: boolean): NodeBuffer;
53 | encrypt(data: Data, publicKeys: IPublicKey[], enablePadding?: boolean): NodeBuffer;
54 | encrypt(
55 | data: Data,
56 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
57 | enablePadding?: boolean,
58 | ): NodeBuffer;
59 | decrypt(encryptedData: Data, privateKey: IPrivateKey): NodeBuffer;
60 | calculateHash(data: Data, algorithm?: unknown): NodeBuffer;
61 | extractPublicKey(privateKey: IPrivateKey): IPublicKey;
62 | calculateSignature(data: Data, privateKey: IPrivateKey): NodeBuffer;
63 | verifySignature(data: Data, signature: Data, publicKey: IPublicKey): boolean;
64 | signAndEncrypt(
65 | data: Data,
66 | privateKey: IPrivateKey,
67 | publicKey: IPublicKey,
68 | enablePadding?: boolean,
69 | ): NodeBuffer;
70 | signAndEncrypt(
71 | data: Data,
72 | privateKey: IPrivateKey,
73 | publicKeys: IPublicKey[],
74 | enablePadding?: boolean,
75 | ): NodeBuffer;
76 | signAndEncrypt(
77 | data: Data,
78 | privateKey: IPrivateKey,
79 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
80 | enablePadding?: boolean,
81 | ): NodeBuffer;
82 | signThenEncrypt(
83 | data: Data,
84 | privateKey: IPrivateKey,
85 | publicKey: IPublicKey,
86 | enablePadding?: boolean,
87 | ): NodeBuffer;
88 | signThenEncrypt(
89 | data: Data,
90 | privateKey: IPrivateKey,
91 | publicKeys: IPublicKey[],
92 | enablePadding?: boolean,
93 | ): NodeBuffer;
94 | signThenEncrypt(
95 | data: Data,
96 | privateKey: IPrivateKey,
97 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
98 | enablePadding?: boolean,
99 | ): NodeBuffer;
100 | decryptAndVerify(encryptedData: Data, privateKey: IPrivateKey, publicKey: IPublicKey): NodeBuffer;
101 | decryptAndVerify(
102 | encryptedData: Data,
103 | privateKey: IPrivateKey,
104 | publicKeys: IPublicKey[],
105 | ): NodeBuffer;
106 | decryptAndVerify(
107 | encryptedData: Data,
108 | privateKey: IPrivateKey,
109 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
110 | ): NodeBuffer;
111 | decryptThenVerify(
112 | encryptedData: Data,
113 | privateKey: IPrivateKey,
114 | publicKey: IPublicKey,
115 | ): NodeBuffer;
116 | decryptThenVerify(
117 | encryptedData: Data,
118 | privateKey: IPrivateKey,
119 | publicKeys: IPublicKey[],
120 | ): NodeBuffer;
121 | decryptThenVerify(
122 | encryptedData: Data,
123 | privateKey: IPrivateKey,
124 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
125 | ): NodeBuffer;
126 | getRandomBytes(length: number): NodeBuffer;
127 | signThenEncryptDetached(
128 | data: Data,
129 | privateKey: IPrivateKey,
130 | publicKey: IPublicKey,
131 | enablePadding?: boolean,
132 | ): { encryptedData: NodeBuffer; metadata: NodeBuffer };
133 | signThenEncryptDetached(
134 | data: Data,
135 | privateKey: IPrivateKey,
136 | publicKeys: IPublicKey[],
137 | enablePadding?: boolean,
138 | ): { encryptedData: NodeBuffer; metadata: NodeBuffer };
139 | signThenEncryptDetached(
140 | data: Data,
141 | privateKey: IPrivateKey,
142 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
143 | enablePadding?: boolean,
144 | ): { encryptedData: NodeBuffer; metadata: NodeBuffer };
145 | decryptThenVerifyDetached(
146 | encryptedData: Data,
147 | metadata: Data,
148 | privateKey: IPrivateKey,
149 | publicKey: IPublicKey,
150 | ): NodeBuffer;
151 | decryptThenVerifyDetached(
152 | encryptedData: Data,
153 | metadata: Data,
154 | privateKey: IPrivateKey,
155 | publicKeys: IPublicKey[],
156 | ): NodeBuffer;
157 | decryptThenVerifyDetached(
158 | encryptedData: Data,
159 | metadata: Data,
160 | privateKey: IPrivateKey,
161 | publicKeyOrPublicKeys: IPublicKey | IPublicKey[],
162 | ): NodeBuffer;
163 | generateGroupSession(groupId: Data): IGroupSession;
164 | importGroupSession(epochMessages: Data[]): IGroupSession;
165 | calculateGroupSessionId(groupId: Data): string;
166 | }
167 |
168 | export interface IAccessTokenSigner {
169 | getAlgorithm(): string;
170 | generateTokenSignature(token: Data, privateKey: IPrivateKey): NodeBuffer;
171 | verifyTokenSignature(token: Data, signature: Data, publicKey: IPublicKey): boolean;
172 | }
173 |
174 | export interface ICardCrypto {
175 | generateSignature(data: Data, privateKey: IPrivateKey): NodeBuffer;
176 | verifySignature(data: Data, signature: Data, publicKey: IPublicKey): boolean;
177 | exportPublicKey(publicKey: IPublicKey): NodeBuffer;
178 | importPublicKey(rawPublicKey: Data): IPublicKey;
179 | generateSha512(data: Data): NodeBuffer;
180 | }
181 |
182 | export interface IPrivateKeyExporter {
183 | exportPrivateKey(privateKey: IPrivateKey): NodeBuffer;
184 | importPrivateKey(rawPrivateKey: Data): IPrivateKey;
185 | }
186 |
187 | export interface IPythiaTransformationKeyPair {
188 | privateKey: NodeBuffer;
189 | publicKey: NodeBuffer;
190 | }
191 |
192 | export interface IBrainKeyCrypto {
193 | blind(password: Data): { blindedPassword: NodeBuffer; blindingSecret: NodeBuffer };
194 | deblind(options: { transformedPassword: Data; blindingSecret: Data }): NodeBuffer;
195 | }
196 |
197 | export interface IPythiaCrypto extends IBrainKeyCrypto {
198 | computeTransformationKeyPair(options: {
199 | transformationKeyId: Data;
200 | pythiaSecret: Data;
201 | pythiaScopeSecret: Data;
202 | }): IPythiaTransformationKeyPair;
203 | transform(options: {
204 | blindedPassword: Data;
205 | tweak: Data;
206 | transformationPrivateKey: Data;
207 | }): { transformedPassword: NodeBuffer; transformedTweak: NodeBuffer };
208 | prove(options: {
209 | transformedPassword: Data;
210 | blindedPassword: Data;
211 | transformedTweak: Data;
212 | transformationKeyPair: IPythiaTransformationKeyPair;
213 | }): { proofValueC: NodeBuffer; proofValueU: NodeBuffer };
214 | verify(options: {
215 | transformedPassword: Data;
216 | blindedPassword: Data;
217 | tweak: Data;
218 | transformationPublicKey: Data;
219 | proofValueC: Data;
220 | proofValueU: Data;
221 | }): boolean;
222 | getPasswordUpdateToken(options: {
223 | oldTransformationPrivateKey: Data;
224 | newTransformationPrivateKey: Data;
225 | }): NodeBuffer;
226 | updateDeblindedWithToken(options: { deblindedPassword: Data; updateToken: Data }): NodeBuffer;
227 | }
228 |
--------------------------------------------------------------------------------
/packages/crypto-types/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/crypto-types",
3 | "version": "2.0.0",
4 | "description": "Types for Virgil JavaScript libraries",
5 | "typings": "./index.d.ts",
6 | "files": [
7 | "index.d.ts"
8 | ],
9 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/crypto-types",
10 | "author": "Virgil Security Inc. ",
11 | "license": "BSD-3-Clause",
12 | "dependencies": {
13 | "@types/node": "^13.1.8"
14 | },
15 | "publishConfig": {
16 | "access": "public"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/data-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/data-utils",
3 | "version": "2.0.0",
4 | "description": "Library that contains different functions / classes that are used for data manipulation in different Virgil Security libraries.",
5 | "main": "./dist/node.cjs.js",
6 | "module": "./dist/node.es.js",
7 | "browser": {
8 | "./dist/node.cjs.js": "./dist/browser.cjs.js",
9 | "./dist/node.es.js": "./dist/browser.es.js"
10 | },
11 | "typings": "./dist/types/node.d.ts",
12 | "files": [
13 | "dist"
14 | ],
15 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/data-utils",
16 | "author": "Virgil Security Inc. ",
17 | "license": "BSD-3-Clause",
18 | "scripts": {
19 | "test": "mocha -r ts-node/register src/**/*.test.ts",
20 | "build": "rollup -c",
21 | "clean": "rimraf .rpt2_cache dist",
22 | "prepare": "npm run clean && npm run build"
23 | },
24 | "dependencies": {
25 | "@virgilsecurity/crypto-types": "2.0.0",
26 | "buffer": "^5.4.3",
27 | "html-webpack-plugin": "5.5.1"
28 | },
29 | "devDependencies": {
30 | "@rollup/plugin-commonjs": "24.1.0",
31 | "@rollup/plugin-node-resolve": "15.0.2",
32 | "@rollup/plugin-typescript": "11.1.0",
33 | "@types/chai": "^4.2.7",
34 | "@types/mocha": "^5.2.7",
35 | "chai": "^4.2.0",
36 | "mocha": "^10.2.0",
37 | "rimraf": "^3.0.0",
38 | "rollup": "3.21.0",
39 | "rollup-plugin-commonjs": "^10.1.0",
40 | "rollup-plugin-node-resolve": "^5.2.0",
41 | "rollup-plugin-typescript2": "0.34.1",
42 | "ts-node": "10.9.1",
43 | "typescript": "5.0.4"
44 | },
45 | "publishConfig": {
46 | "access": "public"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/data-utils/rollup.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const commonjs = require('rollup-plugin-commonjs');
4 | const nodeResolve = require('rollup-plugin-node-resolve');
5 | const typescript = require('rollup-plugin-typescript2');
6 |
7 | const FORMAT = {
8 | CJS: 'cjs',
9 | ES: 'es',
10 | };
11 |
12 | const sourcePath = path.join(__dirname, 'src');
13 | const outputPath = path.join(__dirname, 'dist');
14 |
15 | const createNodeEntry = format => ({
16 | external: ['buffer/'],
17 | input: path.join(sourcePath, 'node.ts'),
18 | output: {
19 | format,
20 | file: path.join(outputPath, `node.${format}.js`),
21 | },
22 | plugins: [
23 | typescript({
24 | useTsconfigDeclarationDir: true,
25 | tsconfigOverride: {
26 | compilerOptions: {
27 | declarationDir: path.join(outputPath, 'types'),
28 | },
29 | exclude: [outputPath, '**/*.test.ts'],
30 | },
31 | }),
32 | ],
33 | });
34 |
35 | const createBrowserEntry = format => ({
36 | input: path.join(sourcePath, 'browser.ts'),
37 | output: {
38 | format,
39 | file: path.join(outputPath, `browser.${format}.js`),
40 | },
41 | plugins: [
42 | nodeResolve({ browser: true }),
43 | commonjs(),
44 | typescript({
45 | useTsconfigDeclarationDir: true,
46 | tsconfigOverride: {
47 | compilerOptions: {
48 | declarationDir: path.join(outputPath, 'types'),
49 | },
50 | exclude: [outputPath, '**/*.test.ts'],
51 | },
52 | }),
53 | ],
54 | });
55 |
56 | module.exports = [
57 | createBrowserEntry(FORMAT.CJS),
58 | createBrowserEntry(FORMAT.ES),
59 | createNodeEntry(FORMAT.CJS),
60 | createNodeEntry(FORMAT.ES),
61 | ];
62 |
--------------------------------------------------------------------------------
/packages/data-utils/src/__tests__/browser.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { Buffer as BrowserBuffer } from 'buffer/';
4 |
5 | describe('browser', () => {
6 | it('exports correct Buffer', () => {
7 | // eslint-disable-next-line @typescript-eslint/no-var-requires
8 | const { NodeBuffer } = require('../browser');
9 | expect(NodeBuffer).to.eql(BrowserBuffer);
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/packages/data-utils/src/__tests__/dataToUint8Array.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { createDataToUint8ArrayFunction } from '../dataToUint8Array';
4 |
5 | describe('dataToUint8Array', () => {
6 | let dataToUint8Array: ReturnType;
7 |
8 | before(() => {
9 | dataToUint8Array = createDataToUint8ArrayFunction(Buffer);
10 | });
11 |
12 | it('returns Uint8Array based on a string that was converted to it using defaultEncoding', () => {
13 | const data = 'data';
14 | const result = dataToUint8Array(data, 'utf8');
15 | const expected = Buffer.from(data, 'utf8');
16 | expect(expected.equals(result)).to.be.true;
17 | });
18 |
19 | it('returns Uint8Array based on a string that was converted to it using default encoding (utf-8)', () => {
20 | const data = 'data';
21 | const result = dataToUint8Array(data);
22 | const expected = Buffer.from(data, 'utf8');
23 | expect(expected.equals(result)).to.be.true;
24 | });
25 |
26 | it('returns the same Uint8Array if argument is an instance of Uint8Array', () => {
27 | const data = new Uint8Array(0);
28 | const result = dataToUint8Array(data);
29 | expect(result).to.eql(data);
30 | });
31 |
32 | it('throws if first argument is not a string / Data object / Uint8Array', () => {
33 | const error = () => {
34 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
35 | // @ts-ignore
36 | dataToUint8Array(123);
37 | };
38 | expect(error).to.throw;
39 | });
40 |
41 | it('throws if Data object is invalid', () => {
42 | const error = () => {
43 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
44 | // @ts-ignore
45 | dataToUint8Array({ value: 123, encoding: 'utf8' });
46 | };
47 | expect(error).to.throw;
48 | });
49 |
50 | it('throws if default encoding is invalid', () => {
51 | const error = () => {
52 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
53 | // @ts-ignore
54 | dataToUint8Array('123', 'hello');
55 | };
56 | expect(error).to.throw;
57 | });
58 |
59 | it("throws if Data object's encoding is invalid", () => {
60 | const error = () => {
61 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
62 | // @ts-ignore
63 | dataToUint8Array({ value: '123', encoding: 'hello' });
64 | };
65 | expect(error).to.throw;
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/packages/data-utils/src/__tests__/node.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | describe('node', () => {
4 | it('exports correct Buffer', () => {
5 | // eslint-disable-next-line @typescript-eslint/no-var-requires
6 | const { NodeBuffer } = require('../node');
7 | expect(NodeBuffer).to.eql(global.Buffer);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/packages/data-utils/src/__tests__/toBuffer.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { createToBufferFunction } from '../toBuffer';
4 |
5 | describe('toBuffer', () => {
6 | let toBuffer: ReturnType;
7 |
8 | before(() => {
9 | toBuffer = createToBufferFunction(Buffer);
10 | });
11 |
12 | it('returns correct buffer', () => {
13 | const data = Buffer.from('data', 'utf8');
14 | const result = toBuffer(data);
15 | expect(result.buffer).to.eql(data.buffer);
16 | });
17 |
18 | it("returns correct buffer respecting the buffer's view", () => {
19 | const data = Buffer.from('data', 'utf8').subarray(0, 1);
20 | const result = toBuffer(data);
21 | expect(result).to.eql(Buffer.from('d', 'utf8'));
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/data-utils/src/browser.ts:
--------------------------------------------------------------------------------
1 | import { Buffer as NodeBuffer } from 'buffer/';
2 |
3 | import { createDataToUint8ArrayFunction } from './dataToUint8Array';
4 | import { createToBufferFunction } from './toBuffer';
5 |
6 | export { Buffer as NodeBuffer } from 'buffer/';
7 |
8 | export const dataToUint8Array = createDataToUint8ArrayFunction(NodeBuffer);
9 | export const toBuffer = createToBufferFunction(NodeBuffer);
10 |
--------------------------------------------------------------------------------
/packages/data-utils/src/dataToUint8Array.ts:
--------------------------------------------------------------------------------
1 | import { Data, StringEncoding } from './types';
2 |
3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
4 | export const createDataToUint8ArrayFunction = (NodeBuffer: any) => (
5 | data: Data,
6 | defaultEncoding?: StringEncoding,
7 | ): Uint8Array => {
8 | if (typeof data === 'string') {
9 | if (typeof defaultEncoding === 'string' && !NodeBuffer.isEncoding(defaultEncoding)) {
10 | throw new TypeError('Invalid default encoding.');
11 | }
12 | return NodeBuffer.from(data, defaultEncoding);
13 | }
14 | if (data instanceof Uint8Array) {
15 | return data;
16 | }
17 | if (
18 | typeof data === 'object' &&
19 | typeof data.value === 'string' &&
20 | NodeBuffer.isEncoding(data.encoding)
21 | ) {
22 | return NodeBuffer.from(data.value, data.encoding);
23 | }
24 | throw new TypeError("Invalid format of 'Data'.");
25 | };
26 |
--------------------------------------------------------------------------------
/packages/data-utils/src/node.ts:
--------------------------------------------------------------------------------
1 | import { createDataToUint8ArrayFunction } from './dataToUint8Array';
2 | import { createToBufferFunction } from './toBuffer';
3 |
4 | export const NodeBuffer = global.Buffer;
5 | export const dataToUint8Array = createDataToUint8ArrayFunction(NodeBuffer);
6 | export const toBuffer = createToBufferFunction(NodeBuffer);
7 |
--------------------------------------------------------------------------------
/packages/data-utils/src/toBuffer.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer as BufferType } from './types';
2 |
3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
4 | export const createToBufferFunction = (NodeBuffer: any) => (array: Uint8Array): BufferType => {
5 | let buffer = NodeBuffer.from(array.buffer);
6 | if (array.byteLength !== array.buffer.byteLength) {
7 | buffer = buffer.slice(array.byteOffset, array.byteOffset + array.byteLength);
8 | }
9 | return buffer;
10 | };
11 |
--------------------------------------------------------------------------------
/packages/data-utils/src/types.ts:
--------------------------------------------------------------------------------
1 | export type NodeBuffer = import('@virgilsecurity/crypto-types').NodeBuffer;
2 | export type Data = import('@virgilsecurity/crypto-types').Data;
3 | export type StringEncoding = import('@virgilsecurity/crypto-types').StringEncoding;
4 |
--------------------------------------------------------------------------------
/packages/data-utils/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "declaration": true,
5 | "esModuleInterop": true,
6 | "moduleResolution": "node",
7 | "resolveJsonModule": true,
8 | "strict": true,
9 | "target": "es2015"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/init-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/init-utils",
3 | "version": "2.0.0",
4 | "description": "Initialization utility for Virgil Security Inc. libraries",
5 | "main": "./dist/init-utils.cjs.js",
6 | "module": "./dist/init-utils.es.js",
7 | "typings": "./dist/types/index.d.ts",
8 | "files": [
9 | "dist"
10 | ],
11 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/init-utils",
12 | "author": "Virgil Security Inc. ",
13 | "license": "BSD-3-Clause",
14 | "scripts": {
15 | "test": "mocha -r ts-node/register src/**/*.test.ts",
16 | "build": "rollup -c",
17 | "clean": "rimraf .rpt2_cache dist",
18 | "prepare": "npm run clean && npm run build"
19 | },
20 | "dependencies": {
21 | "eventemitter3": "^4.0.0",
22 | "html-webpack-plugin": "5.5.1"
23 | },
24 | "devDependencies": {
25 | "@rollup/plugin-typescript": "11.1.0",
26 | "@types/chai": "^4.2.7",
27 | "@types/mocha": "^5.2.7",
28 | "chai": "^4.2.0",
29 | "mocha": "^10.2.0",
30 | "rimraf": "^3.0.0",
31 | "rollup": "3.21.0",
32 | "ts-node": "10.9.1",
33 | "typescript": "5.0.4"
34 | },
35 | "publishConfig": {
36 | "access": "public"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/init-utils/rollup.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const typescript = require('rollup-plugin-typescript2');
4 |
5 | const formats = ['cjs', 'es'];
6 |
7 | const sourcePath = path.join(__dirname, 'src');
8 | const outputPath = path.join(__dirname, 'dist');
9 |
10 | const createEntry = format => ({
11 | external: ['eventemitter3'],
12 | input: path.join(sourcePath, 'index.ts'),
13 | output: {
14 | format,
15 | file: path.join(outputPath, `init-utils.${format}.js`),
16 | },
17 | plugins: [
18 | typescript({
19 | useTsconfigDeclarationDir: true,
20 | tsconfigOverride: {
21 | compilerOptions: {
22 | declarationDir: path.join(outputPath, 'types'),
23 | },
24 | exclude: [outputPath, '**/*.test.ts'],
25 | },
26 | }),
27 | ],
28 | });
29 |
30 | module.exports = formats.map(createEntry);
31 |
--------------------------------------------------------------------------------
/packages/init-utils/src/ModuleInitializer.ts:
--------------------------------------------------------------------------------
1 | import EventEmmiter from 'eventemitter3';
2 |
3 | import { ModuleAlreadyExistsError, ModuleNotFoundError } from './errors';
4 |
5 | type InitializationFunction = (...args: any[]) => Promise;
6 |
7 | export enum ModuleInitializerEvents {
8 | load = 'load',
9 | remove = 'remove',
10 | error = 'error',
11 | }
12 |
13 | export class ModuleInitializer extends EventEmmiter {
14 | private readonly initFns = new Map>();
15 | private readonly initPromises = new Map>();
16 | private readonly modules = new Map();
17 | private loadModulesPromise: Promise | undefined;
18 |
19 | addModule = (name: string, initFn: InitializationFunction) => {
20 | if (this.initFns.has(name)) {
21 | const error = new ModuleAlreadyExistsError();
22 | this.emit(ModuleInitializerEvents.error, error, name, initFn);
23 | throw error;
24 | }
25 | this.loadModulesPromise = undefined;
26 | this.initFns.set(name, initFn);
27 | };
28 |
29 | getModule = (name: string) => {
30 | if (!this.modules.has(name)) {
31 | const error = new ModuleNotFoundError();
32 | this.emit(ModuleInitializerEvents.error, error, name);
33 | throw error;
34 | }
35 | return this.modules.get(name) as T;
36 | };
37 |
38 | hasModule = (name: string) => this.modules.has(name);
39 |
40 | setModule = (name: string, module: T) => {
41 | this.modules.set(name, module);
42 | this.emit(ModuleInitializerEvents.load, name, module);
43 | };
44 |
45 | removeModule = (name: string) => {
46 | this.initFns.delete(name);
47 | this.initPromises.delete(name);
48 | if (this.modules.has(name)) {
49 | const module = this.modules.get(name);
50 | this.modules.delete(name);
51 | this.emit(ModuleInitializerEvents.remove, name, module);
52 | }
53 | };
54 |
55 | loadModule = (name: string, ...args: any[]) => {
56 | if (!this.initFns.has(name)) {
57 | const error = new ModuleNotFoundError();
58 | this.emit(ModuleInitializerEvents.error, error, name, ...args);
59 | throw error;
60 | }
61 | if (this.initPromises.has(name)) {
62 | return this.initPromises.get(name)!;
63 | }
64 | const initPromise = this.initFns.get(name)!(...args).then(module => {
65 | this.modules.set(name, module);
66 | this.emit(ModuleInitializerEvents.load, name, module, ...args);
67 | return Promise.resolve();
68 | });
69 | this.initPromises.set(name, initPromise);
70 | return initPromise;
71 | };
72 |
73 | loadModules = (args?: { [name: string]: any[] }) => {
74 | if (this.loadModulesPromise) {
75 | return this.loadModulesPromise;
76 | }
77 | const myArgs = args || {};
78 | const names = Array.from(this.initFns.keys());
79 | const loadModules = names.map(name => {
80 | if (myArgs[name]) {
81 | return this.loadModule(name, ...myArgs[name]);
82 | }
83 | return this.loadModule(name);
84 | });
85 | this.loadModulesPromise = Promise.all(loadModules).then(() => Promise.resolve());
86 | return this.loadModulesPromise;
87 | };
88 | }
89 |
--------------------------------------------------------------------------------
/packages/init-utils/src/__tests__/ModuleInitializer.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { ModuleAlreadyExistsError, ModuleNotFoundError } from '../errors';
4 | import { ModuleInitializer } from '../ModuleInitializer';
5 |
6 | describe('ModuleInitializer', () => {
7 | let moduleInitializer: ModuleInitializer;
8 |
9 | beforeEach(() => {
10 | moduleInitializer = new ModuleInitializer();
11 | });
12 |
13 | describe('addModule', () => {
14 | it("throws 'ModuleAlreadyExistsError' if module already added", () => {
15 | const moduleName = 'module';
16 | moduleInitializer.addModule(moduleName, () => Promise.resolve());
17 | const error = () => moduleInitializer.addModule(moduleName, () => Promise.resolve());
18 | expect(error).to.throw(ModuleAlreadyExistsError);
19 | });
20 | });
21 |
22 | describe('getModule', () => {
23 | it('returns the module', () => {
24 | const moduleName = 'module';
25 | const module = {};
26 | moduleInitializer.setModule(moduleName, module);
27 | const result = moduleInitializer.getModule(moduleName);
28 | expect(result).to.equal(module);
29 | });
30 |
31 | it("throws 'ModuleNotFoundError' if module not found", () => {
32 | const error = () => moduleInitializer.getModule('module');
33 | expect(error).to.throw(ModuleNotFoundError);
34 | });
35 | });
36 |
37 | describe('hasModule', () => {
38 | it('returns true if module was found', () => {
39 | const moduleName = 'module';
40 | moduleInitializer.setModule(moduleName, {});
41 | expect(moduleInitializer.hasModule(moduleName)).to.be.true;
42 | });
43 |
44 | it('returns false if module was not found', () => {
45 | moduleInitializer.setModule('module1', {});
46 | expect(moduleInitializer.hasModule('module2')).to.be.false;
47 | });
48 | });
49 |
50 | describe('setModule', () => {
51 | it('sets the module', () => {
52 | const moduleName = 'module';
53 | moduleInitializer.setModule(moduleName, {});
54 | expect(moduleInitializer.hasModule(moduleName)).to.be.true;
55 | });
56 | });
57 |
58 | describe('removeModule', () => {
59 | it('removes the module', () => {
60 | const moduleName = 'module';
61 | moduleInitializer.setModule(moduleName, {});
62 | moduleInitializer.removeModule(moduleName);
63 | expect(moduleInitializer.hasModule(moduleName)).to.be.false;
64 | });
65 | });
66 |
67 | describe('loadModule', () => {
68 | it('returns memoized promise', async () => {
69 | const moduleName = 'module';
70 | moduleInitializer.addModule(moduleName, () => Promise.resolve());
71 | const promise1 = moduleInitializer.loadModule(moduleName);
72 | await moduleInitializer.loadModule(moduleName);
73 | const promise2 = moduleInitializer.loadModule(moduleName);
74 | expect(promise1).to.equal(promise2);
75 | });
76 |
77 | it("throws 'ModuleNotFoundError' if module was removed", async () => {
78 | const moduleName = 'module';
79 | moduleInitializer.addModule(moduleName, () => Promise.resolve());
80 | moduleInitializer.removeModule(moduleName);
81 | try {
82 | await moduleInitializer.loadModule(moduleName);
83 | } catch (error) {
84 | expect(error).to.be.instanceOf(ModuleNotFoundError);
85 | }
86 | });
87 | });
88 |
89 | describe('loadModules', () => {
90 | it('loads all modules', async () => {
91 | const module1Name = 'module1';
92 | const module1 = {};
93 | const module2Name = 'module2';
94 | const module2 = {};
95 | moduleInitializer.addModule(module1Name, () => Promise.resolve(module1));
96 | moduleInitializer.addModule(module2Name, () => Promise.resolve(module2));
97 | await moduleInitializer.loadModules();
98 | expect(moduleInitializer.getModule(module1Name)).to.equal(module1);
99 | expect(moduleInitializer.getModule(module2Name)).to.equal(module2);
100 | });
101 |
102 | it('returns memoized promise', async () => {
103 | moduleInitializer.addModule('module1', () => Promise.resolve());
104 | moduleInitializer.addModule('module2', () => Promise.resolve());
105 | const promise1 = moduleInitializer.loadModules();
106 | await moduleInitializer.loadModules();
107 | const promise2 = moduleInitializer.loadModules();
108 | expect(promise1).to.equal(promise2);
109 | });
110 |
111 | it('returns new promise if called after new module was added', async () => {
112 | moduleInitializer.addModule('module1', () => Promise.resolve());
113 | moduleInitializer.addModule('module2', () => Promise.resolve());
114 | await moduleInitializer.loadModules();
115 | const promise1 = moduleInitializer.loadModules();
116 | moduleInitializer.addModule('module3', () => Promise.resolve());
117 | const promise2 = moduleInitializer.loadModules();
118 | expect(promise1).not.to.equal(promise2);
119 | });
120 | });
121 |
122 | describe('events', () => {
123 | it("emits 'load' event", done => {
124 | const moduleName = 'module1';
125 | const modulePayload = {};
126 | moduleInitializer.on('load', (name, module) => {
127 | expect(name).to.equal(moduleName);
128 | expect(module).to.equal(modulePayload);
129 | done();
130 | });
131 | moduleInitializer.addModule(moduleName, () => Promise.resolve(modulePayload));
132 | moduleInitializer.loadModules();
133 | });
134 |
135 | it("emits 'remove' event", done => {
136 | const moduleName = 'module1';
137 | const modulePayload = {};
138 | moduleInitializer.on('remove', (name, module) => {
139 | expect(name).to.equal(moduleName);
140 | expect(module).to.equal(modulePayload);
141 | done();
142 | });
143 | moduleInitializer.addModule(moduleName, () => Promise.resolve(modulePayload));
144 | moduleInitializer.loadModules().then(() => {
145 | moduleInitializer.removeModule(moduleName);
146 | });
147 | });
148 |
149 | it("emits 'error' event", done => {
150 | const moduleName = 'module1';
151 | moduleInitializer.on('error', (error, name) => {
152 | expect(error).to.be.instanceOf(ModuleAlreadyExistsError);
153 | expect(name).to.equal(moduleName);
154 | done();
155 | });
156 | moduleInitializer.addModule(moduleName, () => Promise.resolve());
157 | try {
158 | moduleInitializer.addModule(moduleName, () => Promise.resolve());
159 | } catch (error) {
160 | expect(error).to.be.instanceOf(ModuleAlreadyExistsError);
161 | }
162 | });
163 | });
164 | });
165 |
--------------------------------------------------------------------------------
/packages/init-utils/src/errors.ts:
--------------------------------------------------------------------------------
1 | export class ModuleAlreadyExistsError extends Error {
2 | constructor() {
3 | super('Module already exists.');
4 | Object.setPrototypeOf(this, ModuleAlreadyExistsError.prototype);
5 | this.name = 'ModuleAlreadyExistsError';
6 | }
7 | }
8 |
9 | export class ModuleNotFoundError extends Error {
10 | constructor() {
11 | super('Module not found.');
12 | Object.setPrototypeOf(this, ModuleNotFoundError.prototype);
13 | this.name = 'ModuleNotFoundError';
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/init-utils/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './errors';
2 | export { ModuleInitializer, ModuleInitializerEvents } from './ModuleInitializer';
3 |
--------------------------------------------------------------------------------
/packages/init-utils/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "declaration": true,
5 | "esModuleInterop": true,
6 | "moduleResolution": "node",
7 | "resolveJsonModule": true,
8 | "strict": true,
9 | "target": "es2015"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/browser.cjs.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/browser.cjs.js:
--------------------------------------------------------------------------------
1 | const { initPythia } = require('./dist/browser.cjs');
2 | const pythiaWasm = require('./dist/libpythia.browser.wasm');
3 |
4 | const defaultOptions = {
5 | pythia: [{ locateFile: () => pythiaWasm }],
6 | };
7 |
8 | module.exports = require('./dist/browser.cjs');
9 |
10 | module.exports.initPythia = options => initPythia(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/browser.es.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/browser.es.js:
--------------------------------------------------------------------------------
1 | import { initPythia as rawInitPythia } from './dist/browser.es';
2 | import pythiaWasm from './dist/libpythia.browser.wasm';
3 |
4 | export * from './dist/browser.es';
5 |
6 | const defaultOptions = {
7 | pythia: [{ locateFile: () => pythiaWasm }],
8 | };
9 |
10 | export const initPythia = options => rawInitPythia(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/pythia-crypto",
3 | "version": "2.0.0",
4 | "description": "Virgil Pythia Crypto library.",
5 | "main": "./dist/node.cjs.js",
6 | "module": "./dist/node.es.js",
7 | "browser": {
8 | "./dist/node.cjs.js": "./browser.cjs.js",
9 | "./dist/node.es.js": "./browser.es.js"
10 | },
11 | "typings": "./dist/types/index.d.ts",
12 | "files": [
13 | "dist",
14 | "browser.cjs.js",
15 | "browser.cjs.d.ts",
16 | "browser.es.js",
17 | "browser.es.d.ts",
18 | "worker.cjs.js",
19 | "worker.cjs.d.ts",
20 | "worker.es.js"
21 | ],
22 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/pythia-crypto",
23 | "author": "Virgil Security Inc. ",
24 | "license": "BSD-3-Clause",
25 | "scripts": {
26 | "test": "mocha -t 0 -r ts-node/register src/**/*.test.ts",
27 | "build": "rollup -c",
28 | "clean": "rimraf .rpt2_cache dist",
29 | "prepare": "npm run clean && npm run build"
30 | },
31 | "dependencies": {
32 | "@virgilsecurity/core-pythia": "^2.0.0",
33 | "@virgilsecurity/crypto-types": "^2.0.0",
34 | "@virgilsecurity/data-utils": "^2.0.0",
35 | "@virgilsecurity/init-utils": "^2.0.0",
36 | "html-webpack-plugin": "5.5.1"
37 | },
38 | "devDependencies": {
39 | "@rollup/plugin-commonjs": "24.1.0",
40 | "@rollup/plugin-node-resolve": "15.0.2",
41 | "@rollup/plugin-terser": "0.4.1",
42 | "@rollup/plugin-typescript": "11.1.0",
43 | "@types/chai": "^4.2.7",
44 | "@types/mocha": "^5.2.7",
45 | "chai": "^4.2.0",
46 | "mocha": "^10.2.0",
47 | "rimraf": "^3.0.0",
48 | "rollup": "3.21.0",
49 | "rollup-plugin-copy": "3.4.0",
50 | "rollup-plugin-re": "1.0.7",
51 | "ts-node": "10.9.1",
52 | "typescript": "5.0.4"
53 | },
54 | "publishConfig": {
55 | "access": "public"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/rollup.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const builtinModules = require('builtin-modules');
4 | const commonjs = require('@rollup/plugin-commonjs');
5 | const copy = require('rollup-plugin-copy');
6 | const nodeResolve = require('@rollup/plugin-node-resolve');
7 | const replace = require('rollup-plugin-re');
8 | const terser = require('@rollup/plugin-terser');
9 | const typescript = require('@rollup/plugin-typescript');
10 |
11 | const packageJson = require('./package.json');
12 | const { createDeclarationForInnerEntry } = require('../../utils/rollup-common-configs');
13 | const {
14 | FORMAT,
15 | CRYPTO_TYPE,
16 | TARGET,
17 | getOutputFilename,
18 | getCryptoEntryPointName,
19 | } = require('../../utils/build');
20 |
21 | const sourceDir = path.join(__dirname, 'src');
22 | const outputDir = path.join(__dirname, 'dist');
23 | const corePythiaDir = path.parse(require.resolve('@virgilsecurity/core-pythia')).dir;
24 |
25 | const createBrowserEntry = (target, cryptoType, format, declaration = false) => {
26 | const pythiaEntryPoint = path.join(
27 | '@virgilsecurity',
28 | 'core-pythia',
29 | getCryptoEntryPointName(target, cryptoType, format),
30 | );
31 | return {
32 | input: path.join(sourceDir, 'index.ts'),
33 | output: {
34 | format,
35 | file: path.join(outputDir, getOutputFilename(target, cryptoType, format)),
36 | name: 'VirgilPythiaCrypto',
37 | },
38 | external:
39 | format !== FORMAT.ES &&
40 | format !== FORMAT.UMD &&
41 | Object.keys(packageJson.dependencies).concat([pythiaEntryPoint]),
42 | plugins: [
43 | replace({
44 | patterns: [
45 | {
46 | match: /(initPythia|types)\.ts$/,
47 | test: '@virgilsecurity/core-pythia',
48 | replace: pythiaEntryPoint,
49 | },
50 | ],
51 | }),
52 | nodeResolve({ browser: true, extensions: ['.js', '.ts'] }),
53 | commonjs(),
54 | typescript(),
55 | createDeclarationForInnerEntry(target, cryptoType, format, outputDir),
56 | cryptoType === CRYPTO_TYPE.WASM &&
57 | copy({
58 | targets: [
59 | {
60 | src: path.join(corePythiaDir, `libpythia.${target}.wasm`),
61 | dest: outputDir,
62 | },
63 | ],
64 | }),
65 | (format === FORMAT.ES || format === FORMAT.UMD) && terser(),
66 | ],
67 | };
68 | };
69 |
70 | const createNodeJsEntry = (cryptoType, format) => {
71 | const pythiaEntryPoint = path.join(
72 | '@virgilsecurity',
73 | 'core-pythia',
74 | getCryptoEntryPointName(TARGET.NODE, cryptoType, format),
75 | );
76 | return {
77 | input: path.join(sourceDir, 'index.ts'),
78 | output: {
79 | format,
80 | file: path.join(outputDir, getOutputFilename(TARGET.NODE, cryptoType, format)),
81 | },
82 | external: builtinModules
83 | .concat(Object.keys(packageJson.dependencies))
84 | .concat([pythiaEntryPoint]),
85 | plugins: [
86 | replace({
87 | patterns: [
88 | {
89 | match: /(initPythia|types)\.ts$/,
90 | test: '@virgilsecurity/core-pythia',
91 | replace: pythiaEntryPoint,
92 | },
93 | ],
94 | }),
95 | nodeResolve({ extensions: ['.js', '.ts'] }),
96 | commonjs(),
97 | typescript(),
98 | createDeclarationForInnerEntry(TARGET.NODE, cryptoType, format, outputDir),
99 | ],
100 | };
101 | };
102 |
103 | module.exports = [
104 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.ASMJS, FORMAT.CJS, true),
105 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.ASMJS, FORMAT.ES),
106 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.ASMJS, FORMAT.UMD),
107 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.WASM, FORMAT.CJS),
108 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.WASM, FORMAT.ES),
109 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.WASM, FORMAT.UMD),
110 | createNodeJsEntry(CRYPTO_TYPE.ASMJS, FORMAT.CJS),
111 | createNodeJsEntry(CRYPTO_TYPE.ASMJS, FORMAT.ES),
112 | createNodeJsEntry(CRYPTO_TYPE.WASM, FORMAT.CJS),
113 | createNodeJsEntry(CRYPTO_TYPE.WASM, FORMAT.ES),
114 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.ASMJS, FORMAT.CJS),
115 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.ASMJS, FORMAT.ES),
116 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.ASMJS, FORMAT.UMD),
117 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.WASM, FORMAT.CJS),
118 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.WASM, FORMAT.ES),
119 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.WASM, FORMAT.UMD),
120 | ];
121 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/VirgilBrainKeyCrypto.ts:
--------------------------------------------------------------------------------
1 | import { dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { getPythiaModules } from './pythiaModules';
4 | import { Data, IBrainKeyCrypto } from './types';
5 |
6 | export class VirgilBrainKeyCrypto implements IBrainKeyCrypto {
7 | blind(password: Data) {
8 | const { Pythia } = getPythiaModules();
9 | const myPassword = dataToUint8Array(password, 'utf8');
10 | const { blindedPassword, blindingSecret } = Pythia.blind(myPassword);
11 | return {
12 | blindedPassword: toBuffer(blindedPassword),
13 | blindingSecret: toBuffer(blindingSecret),
14 | };
15 | }
16 |
17 | deblind(options: { transformedPassword: Data; blindingSecret: Data }) {
18 | const { Pythia } = getPythiaModules();
19 | const myTransformedPassword = dataToUint8Array(options.transformedPassword, 'base64');
20 | const myBlindingSecret = dataToUint8Array(options.blindingSecret, 'base64');
21 | const result = Pythia.deblind(myTransformedPassword, myBlindingSecret);
22 | return toBuffer(result);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/VirgilPythiaCrypto.ts:
--------------------------------------------------------------------------------
1 | import { dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { getPythiaModules } from './pythiaModules';
4 | import { Data, IPythiaTransformationKeyPair, IPythiaCrypto } from './types';
5 | import { VirgilBrainKeyCrypto } from './VirgilBrainKeyCrypto';
6 |
7 | export class VirgilPythiaCrypto implements IPythiaCrypto {
8 | private readonly virgilBrainKeyCrypto: VirgilBrainKeyCrypto;
9 |
10 | constructor(virgilBrainKeyCrypto?: VirgilBrainKeyCrypto) {
11 | this.virgilBrainKeyCrypto = virgilBrainKeyCrypto || new VirgilBrainKeyCrypto();
12 | }
13 |
14 | blind(password: Data) {
15 | return this.virgilBrainKeyCrypto.blind(password);
16 | }
17 |
18 | deblind(options: { transformedPassword: Data; blindingSecret: Data }) {
19 | return this.virgilBrainKeyCrypto.deblind(options);
20 | }
21 |
22 | computeTransformationKeyPair(options: {
23 | transformationKeyId: Data;
24 | pythiaSecret: Data;
25 | pythiaScopeSecret: Data;
26 | }) {
27 | const { Pythia } = getPythiaModules();
28 | const myTransformationKeyId = dataToUint8Array(options.transformationKeyId, 'base64');
29 | const myPythiaSecret = dataToUint8Array(options.pythiaSecret, 'base64');
30 | const myPythiaScopeSecret = dataToUint8Array(options.pythiaScopeSecret, 'base64');
31 | const {
32 | transformationPrivateKey,
33 | transformationPublicKey,
34 | } = Pythia.computeTransformationKeyPair(
35 | myTransformationKeyId,
36 | myPythiaSecret,
37 | myPythiaScopeSecret,
38 | );
39 | return {
40 | privateKey: toBuffer(transformationPrivateKey),
41 | publicKey: toBuffer(transformationPublicKey),
42 | };
43 | }
44 |
45 | transform(options: { blindedPassword: Data; tweak: Data; transformationPrivateKey: Data }) {
46 | const { Pythia } = getPythiaModules();
47 | const myBlindedPassword = dataToUint8Array(options.blindedPassword, 'base64');
48 | const myTweak = dataToUint8Array(options.tweak, 'base64');
49 | const myTransformationPrivateKey = dataToUint8Array(options.transformationPrivateKey, 'base64');
50 | const { transformedPassword, transformedTweak } = Pythia.transform(
51 | myBlindedPassword,
52 | myTweak,
53 | myTransformationPrivateKey,
54 | );
55 | return {
56 | transformedPassword: toBuffer(transformedPassword),
57 | transformedTweak: toBuffer(transformedTweak),
58 | };
59 | }
60 |
61 | prove(options: {
62 | transformedPassword: Data;
63 | blindedPassword: Data;
64 | transformedTweak: Data;
65 | transformationKeyPair: IPythiaTransformationKeyPair;
66 | }) {
67 | const { Pythia } = getPythiaModules();
68 | const myTransformedPassword = dataToUint8Array(options.transformedPassword, 'base64');
69 | const myBlindedPassword = dataToUint8Array(options.blindedPassword, 'base64');
70 | const myTransformedTweak = dataToUint8Array(options.transformedTweak, 'base64');
71 | const { proofValueC, proofValueU } = Pythia.prove(
72 | myTransformedPassword,
73 | myBlindedPassword,
74 | myTransformedTweak,
75 | options.transformationKeyPair.privateKey,
76 | options.transformationKeyPair.publicKey,
77 | );
78 | return {
79 | proofValueC: toBuffer(proofValueC),
80 | proofValueU: toBuffer(proofValueU),
81 | };
82 | }
83 |
84 | verify(options: {
85 | transformedPassword: Data;
86 | blindedPassword: Data;
87 | tweak: Data;
88 | transformationPublicKey: Data;
89 | proofValueC: Data;
90 | proofValueU: Data;
91 | }) {
92 | const { Pythia } = getPythiaModules();
93 | const myTransformedPassword = dataToUint8Array(options.transformedPassword, 'base64');
94 | const myBlindedPassword = dataToUint8Array(options.blindedPassword, 'base64');
95 | const myTweak = dataToUint8Array(options.tweak, 'base64');
96 | const myTransformationPublicKey = dataToUint8Array(options.transformationPublicKey, 'base64');
97 | const myProofValueC = dataToUint8Array(options.proofValueC, 'base64');
98 | const myProofValueU = dataToUint8Array(options.proofValueU, 'base64');
99 | return Pythia.verify(
100 | myTransformedPassword,
101 | myBlindedPassword,
102 | myTweak,
103 | myTransformationPublicKey,
104 | myProofValueC,
105 | myProofValueU,
106 | );
107 | }
108 |
109 | getPasswordUpdateToken(options: {
110 | oldTransformationPrivateKey: Data;
111 | newTransformationPrivateKey: Data;
112 | }) {
113 | const { Pythia } = getPythiaModules();
114 | const myOldTransformationPrivateKey = dataToUint8Array(
115 | options.oldTransformationPrivateKey,
116 | 'base64',
117 | );
118 | const myNewTransformationPrivateKey = dataToUint8Array(
119 | options.newTransformationPrivateKey,
120 | 'base64',
121 | );
122 | const passwordUpdateToken = Pythia.getPasswordUpdateToken(
123 | myOldTransformationPrivateKey,
124 | myNewTransformationPrivateKey,
125 | );
126 | return toBuffer(passwordUpdateToken);
127 | }
128 |
129 | updateDeblindedWithToken(options: { deblindedPassword: Data; updateToken: Data }) {
130 | const { Pythia } = getPythiaModules();
131 | const myDeblindedPassword = dataToUint8Array(options.deblindedPassword, 'base64');
132 | const myUpdateToken = dataToUint8Array(options.updateToken, 'base64');
133 | const result = Pythia.updateDeblindedWithToken(myDeblindedPassword, myUpdateToken);
134 | return toBuffer(result);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/__tests__/VirgilBrainKeyCrypto.test.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer } from '@virgilsecurity/data-utils';
2 | import { expect } from 'chai';
3 |
4 | import { initPythia, VirgilBrainKeyCrypto, VirgilPythiaCrypto } from '../index';
5 | import data from './data.json';
6 |
7 | const DEBLINDED_PASSWORD = NodeBuffer.from(data.kDeblindedPassword, 'hex');
8 |
9 | const PASSWORD = 'password';
10 | const TRANSFORMATION_KEY_ID = NodeBuffer.from(data.kTransformationKeyID);
11 | const TWEAK = NodeBuffer.from(data.kTweek);
12 | const PYTHIA_SECRET = NodeBuffer.from(data.kPythiaSecret);
13 | const PYTHIA_SCOPE_SECRET = NodeBuffer.from(data.kPythiaScopeSecret);
14 |
15 | describe('VirgilBrainKeyCrypto', () => {
16 | let virgilBrainKeyCrypto: VirgilBrainKeyCrypto;
17 | let virgilPythiaCrypto: VirgilPythiaCrypto;
18 |
19 | before(async () => {
20 | await initPythia();
21 | });
22 |
23 | beforeEach(() => {
24 | virgilBrainKeyCrypto = new VirgilBrainKeyCrypto();
25 | virgilPythiaCrypto = new VirgilPythiaCrypto();
26 | });
27 |
28 | describe('blind', () => {
29 | it('returns `blindedPassword` and `blindingSecret`', () => {
30 | const result = virgilBrainKeyCrypto.blind('password');
31 | expect(Object.keys(result)).to.have.length(2);
32 | expect(result.blindedPassword).to.be.instanceOf(NodeBuffer);
33 | expect(result.blindingSecret).to.be.instanceOf(NodeBuffer);
34 | });
35 | });
36 |
37 | describe('deblind', () => {
38 | it('produces the same result for multiple iterations', () => {
39 | for (let i = 0; i < 10; i += 1) {
40 | const { blindingSecret, blindedPassword } = virgilBrainKeyCrypto.blind(PASSWORD);
41 | const {
42 | privateKey: transformationPrivateKey,
43 | } = virgilPythiaCrypto.computeTransformationKeyPair({
44 | transformationKeyId: TRANSFORMATION_KEY_ID,
45 | pythiaSecret: PYTHIA_SECRET,
46 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
47 | });
48 | const { transformedPassword } = virgilPythiaCrypto.transform({
49 | blindedPassword,
50 | transformationPrivateKey,
51 | tweak: TWEAK,
52 | });
53 | const result = virgilBrainKeyCrypto.deblind({
54 | transformedPassword,
55 | blindingSecret,
56 | });
57 | expect(result.equals(DEBLINDED_PASSWORD)).to.be.true;
58 | }
59 | });
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/__tests__/VirgilPythiaCrypto.test.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer } from '@virgilsecurity/data-utils';
2 | import { expect } from 'chai';
3 |
4 | import { initPythia, VirgilBrainKeyCrypto, VirgilPythiaCrypto } from '../index';
5 | import data from './data.json';
6 |
7 | const PASSWORD = 'password';
8 | const TRANSFORMATION_KEY_ID = NodeBuffer.from(data.kTransformationKeyID);
9 | const TWEAK = NodeBuffer.from(data.kTweek);
10 | const PYTHIA_SECRET = NodeBuffer.from(data.kPythiaSecret);
11 | const NEW_PYTHIA_SECRET = NodeBuffer.from(data.kNewPythiaSecret);
12 | const PYTHIA_SCOPE_SECRET = NodeBuffer.from(data.kPythiaScopeSecret);
13 |
14 | describe('VirgilPythiaCrypto', () => {
15 | let virgilBrainKeyCrypto: VirgilBrainKeyCrypto;
16 | let virgilPythiaCrypto: VirgilPythiaCrypto;
17 |
18 | before(async () => {
19 | await initPythia();
20 | });
21 |
22 | beforeEach(() => {
23 | virgilBrainKeyCrypto = new VirgilBrainKeyCrypto();
24 | virgilPythiaCrypto = new VirgilPythiaCrypto();
25 | });
26 |
27 | describe('computeTransformationKeyPair', () => {
28 | it('computes the transformation key pair deterministically', () => {
29 | const { privateKey, publicKey } = virgilPythiaCrypto.computeTransformationKeyPair({
30 | transformationKeyId: TRANSFORMATION_KEY_ID,
31 | pythiaSecret: PYTHIA_SECRET,
32 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
33 | });
34 | expect(privateKey.equals(NodeBuffer.from(data.kTransformationPrivateKey, 'hex'))).to.be.true;
35 | expect(publicKey.equals(NodeBuffer.from(data.kTransformationPublicKey, 'hex'))).to.be.true;
36 | });
37 | });
38 |
39 | describe('transform', () => {
40 | it('returns `transformedPassword` and `transformedTweak`', () => {
41 | const { blindedPassword } = virgilBrainKeyCrypto.blind(PASSWORD);
42 | const {
43 | privateKey: transformationPrivateKey,
44 | } = virgilPythiaCrypto.computeTransformationKeyPair({
45 | transformationKeyId: TRANSFORMATION_KEY_ID,
46 | pythiaSecret: PYTHIA_SECRET,
47 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
48 | });
49 | const result = virgilPythiaCrypto.transform({
50 | blindedPassword,
51 | transformationPrivateKey,
52 | tweak: TWEAK,
53 | });
54 | expect(Object.keys(result)).to.have.length(2);
55 | expect(result.transformedPassword).to.be.instanceOf(NodeBuffer);
56 | expect(result.transformedTweak).to.be.instanceOf(NodeBuffer);
57 | });
58 | });
59 |
60 | describe('prove', () => {
61 | it('returns `proofValueC` and `proofValueU`', () => {
62 | const { blindedPassword } = virgilBrainKeyCrypto.blind(PASSWORD);
63 | const transformationKeyPair = virgilPythiaCrypto.computeTransformationKeyPair({
64 | transformationKeyId: TRANSFORMATION_KEY_ID,
65 | pythiaSecret: PYTHIA_SECRET,
66 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
67 | });
68 | const { transformedPassword, transformedTweak } = virgilPythiaCrypto.transform({
69 | blindedPassword,
70 | tweak: TWEAK,
71 | transformationPrivateKey: transformationKeyPair.privateKey,
72 | });
73 | const result = virgilPythiaCrypto.prove({
74 | transformedPassword,
75 | blindedPassword,
76 | transformedTweak,
77 | transformationKeyPair,
78 | });
79 | expect(Object.keys(result)).to.have.length(2);
80 | expect(result.proofValueC).to.be.instanceOf(NodeBuffer);
81 | expect(result.proofValueU).to.be.instanceOf(NodeBuffer);
82 | });
83 | });
84 |
85 | describe('verify', () => {
86 | it('verifies transformed password', () => {
87 | const { blindedPassword } = virgilBrainKeyCrypto.blind(PASSWORD);
88 | const transformationKeyPair = virgilPythiaCrypto.computeTransformationKeyPair({
89 | transformationKeyId: TRANSFORMATION_KEY_ID,
90 | pythiaSecret: PYTHIA_SECRET,
91 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
92 | });
93 | const { transformedPassword, transformedTweak } = virgilPythiaCrypto.transform({
94 | blindedPassword,
95 | tweak: TWEAK,
96 | transformationPrivateKey: transformationKeyPair.privateKey,
97 | });
98 | const { proofValueC, proofValueU } = virgilPythiaCrypto.prove({
99 | transformedPassword,
100 | blindedPassword,
101 | transformedTweak,
102 | transformationKeyPair,
103 | });
104 | const verified = virgilPythiaCrypto.verify({
105 | transformedPassword,
106 | blindedPassword,
107 | proofValueC,
108 | proofValueU,
109 | tweak: TWEAK,
110 | transformationPublicKey: transformationKeyPair.publicKey,
111 | });
112 | expect(verified).to.be.true;
113 | });
114 | });
115 |
116 | describe('getPasswordUpdateToken', () => {
117 | it('returns password update token', () => {
118 | const oldTransformationKeyPair = virgilPythiaCrypto.computeTransformationKeyPair({
119 | transformationKeyId: TRANSFORMATION_KEY_ID,
120 | pythiaSecret: PYTHIA_SECRET,
121 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
122 | });
123 | const newTransformationKeyPair = virgilPythiaCrypto.computeTransformationKeyPair({
124 | transformationKeyId: TRANSFORMATION_KEY_ID,
125 | pythiaSecret: NEW_PYTHIA_SECRET,
126 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
127 | });
128 | const updateToken = virgilPythiaCrypto.getPasswordUpdateToken({
129 | oldTransformationPrivateKey: oldTransformationKeyPair.privateKey,
130 | newTransformationPrivateKey: newTransformationKeyPair.privateKey,
131 | });
132 | expect(updateToken).to.be.instanceOf(NodeBuffer);
133 | });
134 | });
135 |
136 | describe('updateDeblindedWithToken', () => {
137 | it('updates deblinded password with token', () => {
138 | const { blindingSecret, blindedPassword } = virgilBrainKeyCrypto.blind(PASSWORD);
139 | const oldTransformationKeyPair = virgilPythiaCrypto.computeTransformationKeyPair({
140 | transformationKeyId: TRANSFORMATION_KEY_ID,
141 | pythiaSecret: PYTHIA_SECRET,
142 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
143 | });
144 | const { transformedPassword } = virgilPythiaCrypto.transform({
145 | blindedPassword,
146 | tweak: TWEAK,
147 | transformationPrivateKey: oldTransformationKeyPair.privateKey,
148 | });
149 | const deblindedPassword = virgilBrainKeyCrypto.deblind({
150 | transformedPassword,
151 | blindingSecret,
152 | });
153 | const newTransformationKeyPair = virgilPythiaCrypto.computeTransformationKeyPair({
154 | transformationKeyId: TRANSFORMATION_KEY_ID,
155 | pythiaSecret: NEW_PYTHIA_SECRET,
156 | pythiaScopeSecret: PYTHIA_SCOPE_SECRET,
157 | });
158 | const updateToken = virgilPythiaCrypto.getPasswordUpdateToken({
159 | oldTransformationPrivateKey: oldTransformationKeyPair.privateKey,
160 | newTransformationPrivateKey: newTransformationKeyPair.privateKey,
161 | });
162 | const updatedDeblindedPassword = virgilPythiaCrypto.updateDeblindedWithToken({
163 | deblindedPassword,
164 | updateToken,
165 | });
166 | const {
167 | blindingSecret: newBlindingSecret,
168 | blindedPassword: newBlindedPassword,
169 | } = virgilBrainKeyCrypto.blind(PASSWORD);
170 | const { transformedPassword: newTransformedPassword } = virgilPythiaCrypto.transform({
171 | blindedPassword: newBlindedPassword,
172 | tweak: TWEAK,
173 | transformationPrivateKey: newTransformationKeyPair.privateKey,
174 | });
175 | const newDeblindedPassword = virgilBrainKeyCrypto.deblind({
176 | transformedPassword: newTransformedPassword,
177 | blindingSecret: newBlindingSecret,
178 | });
179 | expect(updatedDeblindedPassword.equals(newDeblindedPassword)).to.be.true;
180 | });
181 | });
182 | });
183 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/__tests__/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "kDeblindedPassword": "13273238e3119262f86d3213b8eb6b99c093ef48737dfcfae96210f7350e096cbc7e6b992e4e6f705ac3f0a915d1622c1644596408e3d16126ddfa9ce594e9f361b21ef9c82309e5714c09bcd7f7ec5c2666591134c645d45ed8c9703e718ee005fe4b97fc40f69b424728831d0a889cd39be04683dd380daa0df67c38279e3b9fe32f6c40780311f2dfbb6e89fc90ef15fb2c7958e387182dc7ef57f716fdd152a58ac1d3f0d19bfa2f789024333976c69fbe9e24b58d6cd8fa49c5f4d642b00f8e390c199f37f7b3125758ef284ae10fd9c2da7ea280550baccd55dadd70873a063bcfc9cac9079042af88a543a6cc09aaed6ba4954d6ee8ccc6e1145944328266616cd00f8a616f0e79e52ddd2ef970c8ba8f8ffce35505dc643c8e2b6e430a1474a6d043a4daf9b62af87c1d45ca994d23f908f7898a3f44ca7bb642122087ca819308b3d8afad17ca1f6148e8750870336ca68eb783c89b0dc9d92392f453c650e9f09232b9fcffd1c2cad24b14d2b4952b7f54552295ce0e854996913c",
3 | "kPassword": "password",
4 | "kTransformationKeyID": "virgil.com",
5 | "kTweek": "alice",
6 | "kPythiaSecret": "master secret",
7 | "kNewPythiaSecret": "new master secret",
8 | "kPythiaScopeSecret": "server secret",
9 | "kNewPythiaScopeSecret": "new server secret",
10 | "kTransformationPrivateKey": "0065a626a876f31cff1a006d1c0ac0d880cd87b64a1b9b6dba2a8e9515a76c1a90",
11 | "kTransformationPublicKey": "020c2115769847b116893c5e0828f6ebdf9c64a711893ef1d887dbca2e07acc9e94826a96a8533a0af2b20948d242fbe8c",
12 | "kNewTransformationPrivateKey": "002cc79352ddce8adfe7743bd3bb5ad32a338f8cbaa25a7de03f57977e2c0ca671",
13 | "kNewTransformationPublicKey": "0305b6d10221ee1302947197cdf51c9a016773627c63f7477dfad9937c15e37697f00464223220c371502a3d5410715ddf",
14 | "kUpdateToken": "006a71bdc710fd570fca7cc9396a83bd6c1c53ad6466b66754d0a07e9d6ec47239",
15 | "kNewDeblinded": "0da36f16a3bbe85d50eca27418bf7d9d79cccd2822c579b31d211061e751d74e410f48ee545f29ddd1e6351ff82dc8f7160cc7b062fdcd293ba90e8b65ff6b607af28a1e14d9c1c91b3056f3cd9bd543073f8e80189a91c0751fa31400d754d7066516a449043939adffc90c2a0c507df9c7cf4a47f2af87b94ca35c90e7a292a1d3ecce432bd3416e5ed4b460cee78a19ea0f49068aae9cc1173b01320b66ab9ff23f929199718c2508eb1234ec47a2308db8c15197b791bf22850792a0f97411f4b7831861565be8c0c8bc3e3e2529d2bc4f66649ffa52f9fcb30dbf21efb83f8a7eb8abe34f682cd24643e306d280047c8b5be5f50e950ef0b41ccc7b0c6286d30d1cc4d7ade2d9b9b2fea058f603d3767bcd1aea91aba45ebe550bd98f39195d5dacaf5770452d72c5ae171847f642d2aa252511e7961389adae16147450de0fb6a45d2791607e08c7e2278e564908378a78cd1bdfc4f5ffd17433d8272d614357db7002ed3674fe7ee77b2f885f89bfb21f452fd6179868496c1dc576b2"
16 | }
17 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/__tests__/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.json' {
2 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
3 | const value: any;
4 | export = value;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/index.ts:
--------------------------------------------------------------------------------
1 | export {
2 | moduleInitializer,
3 | getPythiaModules,
4 | hasPythiaModules,
5 | setPythiaModules,
6 | initPythia,
7 | } from './pythiaModules';
8 | export { VirgilBrainKeyCrypto } from './VirgilBrainKeyCrypto';
9 | export { VirgilPythiaCrypto } from './VirgilPythiaCrypto';
10 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/pythiaModules.ts:
--------------------------------------------------------------------------------
1 | import initPythiaModules from '@virgilsecurity/core-pythia';
2 | import { ModuleInitializer } from '@virgilsecurity/init-utils';
3 |
4 | import { PythiaModules } from './types';
5 |
6 | export const moduleInitializer = new ModuleInitializer();
7 |
8 | moduleInitializer.addModule('pythia', initPythiaModules);
9 |
10 | moduleInitializer.on('load', (name, modules) => {
11 | if (name === 'pythia') {
12 | try {
13 | modules.Pythia.configure();
14 | } catch (error) {
15 | modules.Pythia.cleanup();
16 | throw error;
17 | }
18 | }
19 | });
20 |
21 | moduleInitializer.on('remove', (name, modules) => {
22 | if (name === 'pythia') {
23 | modules.Pythia.cleanup();
24 | }
25 | });
26 |
27 | export const hasPythiaModules = () => moduleInitializer.hasModule('pythia');
28 |
29 | export const getPythiaModules = () => moduleInitializer.getModule('pythia');
30 |
31 | export const setPythiaModules = (pythiaModules: PythiaModules) => {
32 | moduleInitializer.setModule('pythia', pythiaModules);
33 | };
34 |
35 | export const initPythia = moduleInitializer.loadModules;
36 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/src/types.ts:
--------------------------------------------------------------------------------
1 | export type PythiaModules = import('@virgilsecurity/core-pythia').PythiaModules;
2 |
3 | export type Data = import('@virgilsecurity/crypto-types').Data;
4 | export type IPythiaTransformationKeyPair = import('@virgilsecurity/crypto-types').IPythiaTransformationKeyPair;
5 | export type IBrainKeyCrypto = import('@virgilsecurity/crypto-types').IBrainKeyCrypto;
6 | export type IPythiaCrypto = import('@virgilsecurity/crypto-types').IPythiaCrypto;
7 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "declaration": true,
5 | "outDir": "dist",
6 | "declarationDir": "dist/types",
7 | "rootDir": "src",
8 | "esModuleInterop": true,
9 | "moduleResolution": "node",
10 | "resolveJsonModule": true,
11 | "strict": true,
12 | "target": "es2015"
13 | },
14 | "exclude": ["**/*.test.ts", "dist"]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/workder.cjs.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/worker.cjs.js:
--------------------------------------------------------------------------------
1 | const { initPythia } = require('./dist/worker.cjs');
2 | const pythiaWasm = require('./dist/libpythia.worker.wasm');
3 |
4 | const defaultOptions = {
5 | pythia: [{ locateFile: () => pythiaWasm }],
6 | };
7 |
8 | module.exports = require('./dist/worker.cjs');
9 |
10 | module.exports.initPythia = options => initPythia(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/worker.es.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/pythia-crypto/worker.es.js:
--------------------------------------------------------------------------------
1 | import { initPythia as rawInitPythia } from './dist/worker.es';
2 | import pythiaWasm from './dist/libpythia.worker.wasm';
3 |
4 | export * from './dist/worker.es';
5 |
6 | const defaultOptions = {
7 | pythia: [{ locateFile: () => pythiaWasm }],
8 | };
9 |
10 | export const initPythia = options => rawInitPythia(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@virgilsecurity/sdk-crypto",
3 | "version": "2.0.0",
4 | "description": "Virgil JavaScript Crypto Library is a high-level cryptographic library that allows you to perform all necessary operations for secure storing and transferring data and everything required to become HIPAA and GDPR compliant.",
5 | "main": "./dist/sdk-crypto.cjs.js",
6 | "module": "./dist/sdk-crypto.es.js",
7 | "typings": "./dist/types/index.d.ts",
8 | "files": [
9 | "dist"
10 | ],
11 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/sdk-crypto",
12 | "author": "Virgil Security Inc. ",
13 | "license": "BSD-3-Clause",
14 | "scripts": {
15 | "build": "rollup -c",
16 | "clean": "rimraf .rpt2_cache dist",
17 | "prepare": "npm run clean && npm run build"
18 | },
19 | "dependencies": {
20 | "@virgilsecurity/crypto-types": "2.0.0"
21 | },
22 | "devDependencies": {
23 | "@rollup/plugin-typescript": "11.1.0",
24 | "rimraf": "^3.0.0",
25 | "rollup": "3.21.0",
26 | "typescript": "5.0.4"
27 | },
28 | "publishConfig": {
29 | "access": "public"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/rollup.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const typescript = require('rollup-plugin-typescript2');
4 |
5 | const formats = ['cjs', 'es'];
6 |
7 | const sourcePath = path.join(__dirname, 'src');
8 | const outputPath = path.join(__dirname, 'dist');
9 |
10 | const createEntry = format => ({
11 | input: path.join(sourcePath, 'index.ts'),
12 | output: {
13 | format,
14 | file: path.join(outputPath, `sdk-crypto.${format}.js`),
15 | },
16 | plugins: [
17 | typescript({
18 | useTsconfigDeclarationDir: true,
19 | tsconfigOverride: {
20 | compilerOptions: {
21 | declarationDir: path.join(outputPath, 'types'),
22 | },
23 | exclude: [outputPath, '**/*.test.ts'],
24 | },
25 | }),
26 | ],
27 | });
28 |
29 | module.exports = formats.map(createEntry);
30 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/src/VirgilAccessTokenSigner.ts:
--------------------------------------------------------------------------------
1 | import { IPrivateKey, IPublicKey, ICrypto, IAccessTokenSigner, Data } from './types';
2 |
3 | export class VirgilAccessTokenSigner implements IAccessTokenSigner {
4 | readonly crypto: ICrypto;
5 |
6 | constructor(crypto: ICrypto) {
7 | if (crypto == null) {
8 | throw new Error('`crypto` is required');
9 | }
10 | this.crypto = crypto;
11 | }
12 |
13 | getAlgorithm() {
14 | return 'VEDS512';
15 | }
16 |
17 | generateTokenSignature(token: Data, privateKey: IPrivateKey) {
18 | return this.crypto.calculateSignature(token, privateKey);
19 | }
20 |
21 | verifyTokenSignature(token: Data, signature: Data, publicKey: IPublicKey) {
22 | return this.crypto.verifySignature(token, signature, publicKey);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/src/VirgilCardCrypto.ts:
--------------------------------------------------------------------------------
1 | import { IPrivateKey, IPublicKey, ICrypto, ICardCrypto, Data } from './types';
2 |
3 | export class VirgilCardCrypto implements ICardCrypto {
4 | readonly crypto: ICrypto;
5 |
6 | constructor(crypto: ICrypto) {
7 | if (crypto == null) {
8 | throw new Error('`crypto` is required');
9 | }
10 | this.crypto = crypto;
11 | }
12 |
13 | generateSignature(data: Data, privateKey: IPrivateKey) {
14 | return this.crypto.calculateSignature(data, privateKey);
15 | }
16 |
17 | verifySignature(data: Data, signature: Data, publicKey: IPublicKey) {
18 | return this.crypto.verifySignature(data, signature, publicKey);
19 | }
20 |
21 | exportPublicKey(publicKey: IPublicKey) {
22 | return this.crypto.exportPublicKey(publicKey);
23 | }
24 |
25 | importPublicKey(publicKeyData: Data) {
26 | return this.crypto.importPublicKey(publicKeyData);
27 | }
28 |
29 | generateSha512(data: Data) {
30 | return this.crypto.calculateHash(data);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/src/VirgilPrivateKeyExporter.ts:
--------------------------------------------------------------------------------
1 | import { IPrivateKey, ICrypto, IPrivateKeyExporter, Data } from './types';
2 |
3 | export class VirgilPrivateKeyExporter implements IPrivateKeyExporter {
4 | readonly crypto: ICrypto;
5 |
6 | constructor(crypto: ICrypto) {
7 | if (crypto == null) {
8 | throw new Error('`crypto` is required');
9 | }
10 | this.crypto = crypto;
11 | }
12 |
13 | exportPrivateKey(key: IPrivateKey) {
14 | return this.crypto.exportPrivateKey(key);
15 | }
16 |
17 | importPrivateKey(keyData: Data) {
18 | return this.crypto.importPrivateKey(keyData);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/src/index.ts:
--------------------------------------------------------------------------------
1 | export { VirgilAccessTokenSigner } from './VirgilAccessTokenSigner';
2 | export { VirgilCardCrypto } from './VirgilCardCrypto';
3 | export { VirgilPrivateKeyExporter } from './VirgilPrivateKeyExporter';
4 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/src/types.ts:
--------------------------------------------------------------------------------
1 | export type Data = import('@virgilsecurity/crypto-types').Data;
2 | export type IPrivateKey = import('@virgilsecurity/crypto-types').IPrivateKey;
3 | export type IPublicKey = import('@virgilsecurity/crypto-types').IPublicKey;
4 | export type ICrypto = import('@virgilsecurity/crypto-types').ICrypto;
5 | export type IAccessTokenSigner = import('@virgilsecurity/crypto-types').IAccessTokenSigner;
6 | export type ICardCrypto = import('@virgilsecurity/crypto-types').ICardCrypto;
7 | export type IPrivateKeyExporter = import('@virgilsecurity/crypto-types').IPrivateKeyExporter;
8 |
--------------------------------------------------------------------------------
/packages/sdk-crypto/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "declaration": true,
5 | "esModuleInterop": true,
6 | "moduleResolution": "node",
7 | "resolveJsonModule": true,
8 | "strict": true,
9 | "target": "es2015"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/README.md:
--------------------------------------------------------------------------------
1 | > This README is for virgil-crypto v4. Check the [v3 branch](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/v3) for virgil-crypto v3 docs.
2 |
3 | # Virgil Security JavaScript Crypto Library
4 | [](https://travis-ci.org/VirgilSecurity/virgil-crypto-javascript)
5 | [](https://www.npmjs.com/package/virgil-crypto)
6 | [](https://github.com/VirgilSecurity/virgil/blob/master/LICENSE)
7 |
8 | ### [Introduction](#introduction) | [Library purposes](#library-purposes) | [Getting started](#getting-started) | [Docs](#docs) | [License](#license) | [Contacts](#support)
9 |
10 | ## Introduction
11 | VirgilCrypto is a stack of security libraries (ECIES with Crypto Agility wrapped in Virgil Cryptogram) and an
12 | open-source high-level [cryptographic library](https://github.com/VirgilSecurity/virgil-crypto-c) that allows you to
13 | perform all necessary operations for securely storing and transferring data in your digital solutions. Crypto Library
14 | is written in C++ and is suitable for mobile and server platforms.
15 |
16 | Virgil Security, Inc., guides software developers into the forthcoming security world in which everything will be
17 | encrypted (and passwords will be eliminated). In this world, the days of developers having to raise millions of
18 | dollars to build a secure chat, secure email, secure file-sharing, or a secure anything have come to an end. Now
19 | developers can instead focus on building features that give them a competitive market advantage while end-users can
20 | enjoy the privacy and security they increasingly demand.
21 |
22 | ## Library purposes
23 | - Asymmetric Key Generation
24 | - Encryption/Decryption of data
25 | - Generation/Verification of digital signatures
26 |
27 | ## Getting started
28 | First, you need to install the package from npm:
29 | ```sh
30 | npm install virgil-crypto
31 | ```
32 | > If you are not using npm, follow our [UMD guide](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/guides/umd.md) to get started.
33 |
34 | Second, you need to decide which approach to use in your application. We provide 2 options here:
35 | - WebAssembly. This is our recommended approach. [List of supported browsers](https://caniuse.com/#feat=wasm).
36 | - asm.js. Use it only in case you need to support old web browsers.
37 |
38 | Third, you will need to setup you development environment (skip this step if you are using Node.js):
39 | - [Webpack](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/guides/webpack.md)
40 | - [Create React App](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/guides/create-react-app.md)
41 | - [React Native](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/guides/react-native.md)
42 | > Not found your environment? Create an issue on GitHub and we will try our best to help you. Make sure to describe your environment as much as possible.
43 |
44 | Last, you need to get familiar with [usage examples](guides/usage-examples.md) of the library.
45 |
46 | ## Docs
47 | - [API Reference](http://virgilsecurity.github.io/virgil-crypto-javascript/)
48 | - [Crypto Core Library](https://github.com/VirgilSecurity/virgil-crypto-c)
49 | - [More usage examples](https://developer.virgilsecurity.com/docs/how-to#cryptography)
50 |
51 | ## License
52 | This library is released under the [3-clause BSD License](https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/LICENSE).
53 |
54 | ## Support
55 | Our developer support team is here to help you.
56 |
57 | You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com.
58 |
59 | Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community).
60 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/browser.cjs.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/browser.cjs.js:
--------------------------------------------------------------------------------
1 | const { initCrypto } = require('./dist/browser.cjs');
2 | const foundationWasm = require('./dist/libfoundation.browser.wasm');
3 |
4 | const defaultOptions = {
5 | foundation: [{ locateFile: () => foundationWasm }],
6 | };
7 |
8 | module.exports = require('./dist/browser.cjs');
9 |
10 | module.exports.initCrypto = options => initCrypto(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/browser.es.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/browser.es.js:
--------------------------------------------------------------------------------
1 | import { initCrypto as rawInitCrypto } from './dist/browser.es';
2 | import foundationWasm from './dist/libfoundation.browser.wasm';
3 |
4 | export * from './dist/browser.es';
5 |
6 | const defaultOptions = {
7 | foundation: [{ locateFile: () => foundationWasm }],
8 | };
9 |
10 | export const initCrypto = options => rawInitCrypto(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "virgil-crypto",
3 | "version": "5.1.0",
4 | "description": "Virgil JavaScript Crypto Library is a high-level cryptographic library that allows you to perform all necessary operations for secure storing and transferring data and everything required to become HIPAA and GDPR compliant.",
5 | "main": "./dist/node.cjs.js",
6 | "module": "./dist/node.es.js",
7 | "browser": {
8 | "./dist/node.cjs.js": "./browser.cjs.js",
9 | "./dist/node.es.js": "./browser.es.js"
10 | },
11 | "typings": "./dist/types/index.d.ts",
12 | "files": [
13 | "dist",
14 | "browser.cjs.js",
15 | "browser.cjs.d.ts",
16 | "browser.es.js",
17 | "browser.es.d.ts",
18 | "worker.cjs.js",
19 | "worker.cjs.d.ts",
20 | "worker.es.js",
21 | "worker.es.d.ts"
22 | ],
23 | "repository": "https://github.com/VirgilSecurity/virgil-crypto-javascript/tree/master/packages/virgil-crypto",
24 | "author": "Virgil Security Inc. ",
25 | "license": "BSD-3-Clause",
26 | "keywords": [
27 | "security",
28 | "elliptic",
29 | "elliptic curve",
30 | "virgil",
31 | "virgilsecurity",
32 | "encryption",
33 | "crypto"
34 | ],
35 | "scripts": {
36 | "test": "mocha -t 0 -r ts-node/register src/**/*.test.ts",
37 | "build": "rollup -c",
38 | "clean": "rimraf .rpt2_cache dist",
39 | "prepare": "npm run clean && npm run build"
40 | },
41 | "dependencies": {
42 | "@virgilsecurity/core-foundation": "^2.1.0",
43 | "@virgilsecurity/crypto-types": "^2.0.0",
44 | "@virgilsecurity/data-utils": "^2.0.0",
45 | "@virgilsecurity/init-utils": "^2.0.0",
46 | "@virgilsecurity/sdk-crypto": "^2.0.0",
47 | "html-webpack-plugin": "5.5.1"
48 | },
49 | "devDependencies": {
50 | "@rollup/plugin-wasm": "^6.1.3",
51 | "@rollup/plugin-commonjs": "25.0.7",
52 | "@rollup/plugin-node-resolve": "15.2.3",
53 | "@rollup/plugin-terser": "0.4.4",
54 | "@rollup/plugin-typescript": "11.1.6",
55 | "@types/chai": "^4.2.7",
56 | "@types/mocha": "^5.2.7",
57 | "@types/node": "^13.1.8",
58 | "builtin-modules": "^3.1.0",
59 | "chai": "^4.2.0",
60 | "mocha": "^10.2.0",
61 | "rimraf": "^3.0.0",
62 | "rollup": "3.21.0",
63 | "rollup-plugin-copy": "3.4.0",
64 | "rollup-plugin-re": "1.0.7",
65 | "ts-node": "10.9.2",
66 | "typescript": "5.4.5"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/rollup.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const builtinModules = require('builtin-modules');
4 | const commonjs = require('@rollup/plugin-commonjs');
5 | const copy = require('rollup-plugin-copy');
6 | const nodeResolve = require('@rollup/plugin-node-resolve');
7 | const replace = require('rollup-plugin-re');
8 | const terser = require('@rollup/plugin-terser');
9 | const typescript = require('@rollup/plugin-typescript');
10 | const wasm = require('@rollup/plugin-wasm');
11 |
12 | const packageJson = require('./package.json');
13 | const { createDeclarationForInnerEntry } = require('../../utils/rollup-common-configs');
14 | const {
15 | FORMAT,
16 | CRYPTO_TYPE,
17 | TARGET,
18 | getOutputFilename,
19 | getCryptoEntryPointName,
20 | } = require('../../utils/build');
21 |
22 | const sourceDir = path.join(__dirname, 'src');
23 | const outputDir = path.join(__dirname, 'dist').replaceAll('\\' + '', '/');
24 | const coreFoundationDir = path.parse(require.resolve('@virgilsecurity/core-foundation')).dir.replaceAll('\\' + '', '/');
25 |
26 | const createBrowserEntry = (target, cryptoType, format, declaration = false) => {
27 | const foundationEntryPoint = `@virgilsecurity/core-foundation/${getCryptoEntryPointName(target, cryptoType, format)}`;
28 | return {
29 | input: path.join(sourceDir, 'index.ts'),
30 | output: {
31 | format,
32 | file: path.join(outputDir, getOutputFilename(target, cryptoType, format)),
33 | name: 'VirgilCrypto',
34 | },
35 | external:
36 | format !== FORMAT.ES &&
37 | format !== FORMAT.UMD &&
38 | Object.keys(packageJson.dependencies).concat([foundationEntryPoint]),
39 | plugins: [
40 | replace({
41 | patterns: [
42 | {
43 | match: /foundationModules\.ts$/,
44 | test: '@virgilsecurity/core-foundation',
45 | replace: foundationEntryPoint,
46 | },
47 | ],
48 | }),
49 | nodeResolve({ browser: true, extensions: ['.js', '.ts'] }),
50 | commonjs(),
51 | typescript(),
52 | createDeclarationForInnerEntry(target, cryptoType, format, outputDir),
53 | wasm({
54 | publicPath: outputDir,
55 | sync: [coreFoundationDir + `/libfoundation.${target}.wasm`],
56 | }),
57 | copy({
58 | targets: [
59 | {
60 | src: coreFoundationDir + `/libfoundation.${target}.wasm`,
61 | dest: outputDir,
62 | },
63 | ],
64 | }),
65 | (format === FORMAT.ES || format === FORMAT.UMD) && terser(),
66 | ],
67 | };
68 | };
69 |
70 | const createNodeJsEntry = (cryptoType, format) => {
71 | const foundationEntryPoint = `@virgilsecurity/core-foundation/${getCryptoEntryPointName(TARGET.NODE, cryptoType, format)}`;
72 | return {
73 | input: path.join(sourceDir, 'index.ts'),
74 | output: {
75 | format,
76 | file: path.join(outputDir, getOutputFilename(TARGET.NODE, cryptoType, format)),
77 | },
78 | external: builtinModules
79 | .concat(Object.keys(packageJson.dependencies))
80 | .concat([foundationEntryPoint]),
81 | plugins: [
82 | replace({
83 | patterns: [
84 | {
85 | match: /foundationModules\.ts$/,
86 | test: '@virgilsecurity/core-foundation',
87 | replace: foundationEntryPoint,
88 | },
89 | ],
90 | }),
91 | nodeResolve({ extensions: ['.js', '.ts'] }),
92 | commonjs(),
93 | typescript(),
94 | createDeclarationForInnerEntry(TARGET.NODE, cryptoType, format, outputDir),
95 | ],
96 | };
97 | };
98 |
99 | module.exports = [
100 | createNodeJsEntry(CRYPTO_TYPE.ASMJS, FORMAT.CJS),
101 | createNodeJsEntry(CRYPTO_TYPE.ASMJS, FORMAT.ES),
102 | createNodeJsEntry(CRYPTO_TYPE.WASM, FORMAT.CJS),
103 | createNodeJsEntry(CRYPTO_TYPE.WASM, FORMAT.ES),
104 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.WASM, FORMAT.CJS, true),
105 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.WASM, FORMAT.ES),
106 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.WASM, FORMAT.UMD),
107 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.ASMJS, FORMAT.CJS),
108 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.ASMJS, FORMAT.ES),
109 | createBrowserEntry(TARGET.BROWSER, CRYPTO_TYPE.ASMJS, FORMAT.UMD),
110 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.ASMJS, FORMAT.CJS),
111 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.ASMJS, FORMAT.ES),
112 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.ASMJS, FORMAT.UMD),
113 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.WASM, FORMAT.CJS),
114 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.WASM, FORMAT.ES),
115 | createBrowserEntry(TARGET.WORKER, CRYPTO_TYPE.WASM, FORMAT.UMD),
116 | ];
117 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/HashAlgorithm.ts:
--------------------------------------------------------------------------------
1 | export enum HashAlgorithm {
2 | SHA224 = 'SHA224',
3 | SHA256 = 'SHA256',
4 | SHA384 = 'SHA384',
5 | SHA512 = 'SHA512',
6 | }
7 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/KeyPairType.ts:
--------------------------------------------------------------------------------
1 | import { moduleInitializer } from './foundationModules';
2 | import { FoundationModules } from './types';
3 |
4 | export enum KeyPairType {
5 | DEFAULT = 'DEFAULT',
6 | ED25519 = 'ED25519',
7 | CURVE25519 = 'CURVE25519',
8 | SECP256R1 = 'SECP256R1',
9 | RSA_2048 = 'RSA_2048',
10 | RSA_3072 = 'RSA_3072',
11 | RSA_4096 = 'RSA_4096',
12 | RSA_8192 = 'RSA_8192',
13 | CURVE25519_ROUND5_ED25519_FALCON = 'CURVE25519_ROUND5_ED25519_FALCON',
14 | CURVE25519_ED25519 = 'CURVE25519_ED25519',
15 | }
16 |
17 | export interface KeyPairTypeConfig {
18 | type: KeyPairType;
19 | algId?: FoundationModules.AlgId;
20 | bitlen?: number;
21 | cipherAlgIds?: FoundationModules.AlgId[];
22 | signerAlgIds?: FoundationModules.AlgId[];
23 | }
24 |
25 | export const getKeyPairTypeConfig = (
26 | keyPairType: KeyPairType[keyof KeyPairType],
27 | ): KeyPairTypeConfig => {
28 | const { AlgId } = moduleInitializer.getModule('foundation');
29 | switch (keyPairType) {
30 | case KeyPairType.DEFAULT:
31 | return {
32 | type: KeyPairType.DEFAULT,
33 | algId: AlgId.ED25519,
34 | };
35 | case KeyPairType.ED25519:
36 | return {
37 | type: KeyPairType.ED25519,
38 | algId: AlgId.ED25519,
39 | };
40 | case KeyPairType.CURVE25519:
41 | return {
42 | type: KeyPairType.CURVE25519,
43 | algId: AlgId.CURVE25519,
44 | };
45 | case KeyPairType.SECP256R1:
46 | return {
47 | type: KeyPairType.SECP256R1,
48 | algId: AlgId.SECP256R1,
49 | };
50 | case KeyPairType.RSA_2048:
51 | return {
52 | type: KeyPairType.RSA_2048,
53 | algId: AlgId.RSA,
54 | bitlen: 2048,
55 | };
56 | case KeyPairType.RSA_3072:
57 | return {
58 | type: KeyPairType.RSA_3072,
59 | algId: AlgId.RSA,
60 | bitlen: 3072,
61 | };
62 | case KeyPairType.RSA_4096:
63 | return {
64 | type: KeyPairType.RSA_4096,
65 | algId: AlgId.RSA,
66 | bitlen: 4096,
67 | };
68 | case KeyPairType.RSA_8192:
69 | return {
70 | type: KeyPairType.RSA_8192,
71 | algId: AlgId.RSA,
72 | bitlen: 8192,
73 | };
74 | case KeyPairType.CURVE25519_ROUND5_ED25519_FALCON:
75 | return {
76 | type: KeyPairType.CURVE25519_ROUND5_ED25519_FALCON,
77 | cipherAlgIds: [AlgId.CURVE25519, AlgId.ROUND5_ND_1CCA_5D],
78 | signerAlgIds: [AlgId.ED25519, AlgId.FALCON],
79 | };
80 | case KeyPairType.CURVE25519_ED25519:
81 | return {
82 | type: KeyPairType.CURVE25519_ED25519,
83 | cipherAlgIds: [AlgId.CURVE25519, AlgId.NONE],
84 | signerAlgIds: [AlgId.ED25519, AlgId.NONE],
85 | };
86 | default:
87 | throw new TypeError(`Unknown key pair type '${keyPairType}'.`);
88 | }
89 | };
90 |
91 | export const isRSAKeyPairType = (keyPairType: KeyPairType[keyof KeyPairType]) =>
92 | keyPairType === KeyPairType.RSA_2048 ||
93 | keyPairType === KeyPairType.RSA_3072 ||
94 | keyPairType === KeyPairType.RSA_4096 ||
95 | keyPairType === KeyPairType.RSA_8192;
96 |
97 | export const isCompoundKeyPairType = (keyPairType: KeyPairType[keyof KeyPairType]) =>
98 | keyPairType === KeyPairType.CURVE25519_ROUND5_ED25519_FALCON ||
99 | keyPairType === KeyPairType.CURVE25519_ED25519;
100 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilCryptoError.ts:
--------------------------------------------------------------------------------
1 | export enum VirgilCryptoErrorStatus {
2 | STREAM_ILLEGAL_STATE = 'STREAM_ILLEGAL_STATE',
3 | DATA_NOT_SIGNED = 'DATA_NOT_SIGNED',
4 | SIGNER_NOT_FOUND = 'SIGNER_NOT_FOUND',
5 | INVALID_SIGNATURE = 'INVALID_SIGNATURE',
6 | }
7 |
8 | export class VirgilCryptoError extends Error {
9 | static readonly DEFAULT_MESSAGE =
10 | "Use the 'status' property and 'VirgilCryptoErrorStatus' enum to check for specific error.";
11 |
12 | readonly status: VirgilCryptoErrorStatus;
13 |
14 | constructor(errorStatus: VirgilCryptoErrorStatus, message?: string) {
15 | super(message || VirgilCryptoError.DEFAULT_MESSAGE);
16 | Object.setPrototypeOf(this, VirgilCryptoError.prototype);
17 | this.name = 'VirgilCryptoError';
18 | this.status = errorStatus;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilPrivateKey.ts:
--------------------------------------------------------------------------------
1 | import { toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { IPrivateKey, NodeBuffer } from './types';
4 |
5 | export class VirgilPrivateKey implements IPrivateKey {
6 | public readonly identifier: NodeBuffer;
7 | public readonly lowLevelPrivateKey: FoundationModules.PrivateKey;
8 |
9 | private _isDisposed: boolean;
10 |
11 | get isDisposed() {
12 | return this._isDisposed;
13 | }
14 |
15 | constructor(indentifier: Uint8Array, lowLevelPrivateKey: FoundationModules.PrivateKey) {
16 | this.identifier = toBuffer(indentifier);
17 | this.lowLevelPrivateKey = lowLevelPrivateKey;
18 | this._isDisposed = false;
19 | }
20 |
21 | dispose() {
22 | this.lowLevelPrivateKey.delete();
23 | this._isDisposed = true;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilPublicKey.ts:
--------------------------------------------------------------------------------
1 | import { toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { getFoundationModules } from './foundationModules';
4 | import { FoundationModules, IPublicKey, NodeBuffer } from './types';
5 |
6 | export class VirgilPublicKey implements IPublicKey {
7 | public readonly identifier: NodeBuffer;
8 | public readonly lowLevelPublicKey: FoundationModules.PublicKey;
9 |
10 | private _isDisposed: boolean;
11 |
12 | get isDisposed() {
13 | return this._isDisposed;
14 | }
15 |
16 | get key() {
17 | const foundationModules = getFoundationModules();
18 | const keyAsn1Serializer = new foundationModules.KeyAsn1Serializer();
19 | try {
20 | keyAsn1Serializer.setupDefaults();
21 | return keyAsn1Serializer.serializePublicKey(this.lowLevelPublicKey);
22 | } finally {
23 | keyAsn1Serializer.delete();
24 | }
25 | }
26 |
27 | constructor(identifier: Uint8Array, lowLevelPublicKey: FoundationModules.PublicKey) {
28 | this.identifier = toBuffer(identifier);
29 | this.lowLevelPublicKey = lowLevelPublicKey;
30 | this._isDisposed = false;
31 | }
32 |
33 | dispose() {
34 | this.lowLevelPublicKey.delete();
35 | this._isDisposed = true;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilStreamCipher.ts:
--------------------------------------------------------------------------------
1 | import { dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { DATA_SIGNATURE_KEY } from './constants';
4 | import { getFoundationModules } from './foundationModules';
5 | import { getRandom } from './globalInstances';
6 | import { Data } from './types';
7 | import { toArray } from './utils';
8 | import { validatePublicKeysArray } from './validators';
9 | import { VirgilCryptoErrorStatus, VirgilCryptoError } from './VirgilCryptoError';
10 | import { VirgilPublicKey } from './VirgilPublicKey';
11 |
12 | export class VirgilStreamCipher {
13 | private _isFinished: boolean;
14 | private _isRunning: boolean;
15 | private _isDisposed: boolean;
16 |
17 | private readonly recipientCipher: FoundationModules.RecipientCipher;
18 | private readonly messageInfoCustomParams?: FoundationModules.MessageInfoCustomParams;
19 | private readonly aes256Gcm: FoundationModules.Aes256Gcm;
20 |
21 | get isRunning() {
22 | return this._isRunning;
23 | }
24 |
25 | get isFinished() {
26 | return this._isFinished;
27 | }
28 |
29 | get isDisposed() {
30 | return this._isDisposed;
31 | }
32 |
33 | constructor(arg0: VirgilPublicKey | VirgilPublicKey[], arg1?: Data) {
34 | const foundationModules = getFoundationModules();
35 | const publicKeys = toArray(arg0);
36 | validatePublicKeysArray(publicKeys);
37 | this.recipientCipher = new foundationModules.RecipientCipher();
38 | this.aes256Gcm = new foundationModules.Aes256Gcm();
39 | this.recipientCipher.encryptionCipher = this.aes256Gcm;
40 | this.recipientCipher.random = getRandom();
41 | publicKeys.forEach(publicKey => {
42 | this.recipientCipher.addKeyRecipient(publicKey.identifier, publicKey.lowLevelPublicKey);
43 | });
44 | if (arg1) {
45 | const mySignature = dataToUint8Array(arg1, 'base64');
46 | this.messageInfoCustomParams = this.recipientCipher.customParams();
47 | this.messageInfoCustomParams.addData(DATA_SIGNATURE_KEY, mySignature);
48 | }
49 | this._isFinished = false;
50 | this._isRunning = false;
51 | this._isDisposed = false;
52 | }
53 |
54 | start() {
55 | this.ensureLegalState();
56 | this.recipientCipher.startEncryption();
57 | this._isRunning = true;
58 | return toBuffer(this.recipientCipher.packMessageInfo());
59 | }
60 |
61 | update(data: Data) {
62 | this.ensureLegalState();
63 | this.ensureIsRunning();
64 | const myData = dataToUint8Array(data, 'utf8');
65 | return toBuffer(this.recipientCipher.processEncryption(myData));
66 | }
67 |
68 | final(dispose = true) {
69 | this.ensureLegalState();
70 | this.ensureIsRunning();
71 | try {
72 | return toBuffer(this.recipientCipher.finishEncryption());
73 | } finally {
74 | this._isFinished = true;
75 | this._isRunning = false;
76 | if (dispose) {
77 | this.dispose();
78 | }
79 | }
80 | }
81 |
82 | dispose() {
83 | if (this.messageInfoCustomParams) {
84 | this.messageInfoCustomParams.delete();
85 | }
86 | this.aes256Gcm.delete();
87 | this.recipientCipher.delete();
88 | this._isDisposed = true;
89 | }
90 |
91 | private ensureLegalState() {
92 | if (this._isDisposed) {
93 | throw new VirgilCryptoError(
94 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
95 | "Illegal state. Cannot use cipher after the 'dispose' method has been called.",
96 | );
97 | }
98 | if (this._isFinished) {
99 | throw new VirgilCryptoError(
100 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
101 | "Illegal state. Cannot use cipher after the 'final' method has been called.",
102 | );
103 | }
104 | }
105 |
106 | private ensureIsRunning() {
107 | if (!this._isRunning) {
108 | throw new VirgilCryptoError(
109 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
110 | "Illegal state. Cannot use cipher before the 'start' method.",
111 | );
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilStreamDecipher.ts:
--------------------------------------------------------------------------------
1 | import { dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { DATA_SIGNATURE_KEY } from './constants';
4 | import { getFoundationModules } from './foundationModules';
5 | import { Data } from './types';
6 | import { validatePrivateKey } from './validators';
7 | import { VirgilCryptoErrorStatus, VirgilCryptoError } from './VirgilCryptoError';
8 | import { VirgilPrivateKey } from './VirgilPrivateKey';
9 |
10 | export class VirgilStreamDecipher {
11 | private _isFinished = false;
12 | private _isDisposed = false;
13 |
14 | private readonly recipientCipher: FoundationModules.RecipientCipher;
15 |
16 | get isFinished() {
17 | return this._isFinished;
18 | }
19 |
20 | get isDisposed() {
21 | return this._isDisposed;
22 | }
23 |
24 | constructor(privateKey: VirgilPrivateKey) {
25 | const foundationModules = getFoundationModules();
26 | validatePrivateKey(privateKey);
27 | this.recipientCipher = new foundationModules.RecipientCipher();
28 | try {
29 | this.recipientCipher.startDecryptionWithKey(
30 | privateKey.identifier,
31 | privateKey.lowLevelPrivateKey,
32 | new Uint8Array(),
33 | );
34 | } catch (error) {
35 | this.recipientCipher.delete();
36 | throw error;
37 | }
38 | }
39 |
40 | getSignature() {
41 | if (this._isDisposed) {
42 | throw new VirgilCryptoError(
43 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
44 | "Illegal state. Cannot get signature after the 'dispose' method has been called.",
45 | );
46 | }
47 | if (!this._isFinished) {
48 | throw new VirgilCryptoError(
49 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
50 | "Illegal state. Cannot get signature before the 'final' method has been called.",
51 | );
52 | }
53 | const messageInfoCustomParams = this.recipientCipher.customParams();
54 | try {
55 | return toBuffer(messageInfoCustomParams.findData(DATA_SIGNATURE_KEY));
56 | } finally {
57 | messageInfoCustomParams.delete();
58 | }
59 | }
60 |
61 | update(data: Data) {
62 | this.ensureLegalState();
63 | const myData = dataToUint8Array(data, 'utf8');
64 | return toBuffer(this.recipientCipher.processDecryption(myData));
65 | }
66 |
67 | final(dispose = true) {
68 | this.ensureLegalState();
69 | try {
70 | return toBuffer(this.recipientCipher.finishDecryption());
71 | } finally {
72 | this._isFinished = true;
73 | if (dispose) {
74 | this.dispose();
75 | }
76 | }
77 | }
78 |
79 | dispose() {
80 | this.recipientCipher.delete();
81 | this._isDisposed = true;
82 | }
83 |
84 | private ensureLegalState() {
85 | if (this._isDisposed) {
86 | throw new VirgilCryptoError(
87 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
88 | "Illegal state. Cannot use cipher after the 'dispose' method has been called.",
89 | );
90 | }
91 | if (this._isFinished) {
92 | throw new VirgilCryptoError(
93 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
94 | "Illegal state. Cannot use cipher after the 'final' method has been called.",
95 | );
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilStreamDecryptAndVerify.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer, dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { PADDING_LEN } from './constants';
4 | import { getFoundationModules } from './foundationModules';
5 | import { getRandom } from './globalInstances';
6 | import { FoundationModules, Data } from './types';
7 | import { toArray } from './utils';
8 | import { validatePrivateKey, validatePublicKeysArray } from './validators';
9 | import { VirgilCryptoErrorStatus, VirgilCryptoError } from './VirgilCryptoError';
10 | import { VirgilPrivateKey } from './VirgilPrivateKey';
11 | import { VirgilPublicKey } from './VirgilPublicKey';
12 |
13 | export class VirgilStreamDecryptAndVerify {
14 | private _isDisposed: boolean;
15 | private _isFinished: boolean;
16 |
17 | private readonly paddingParams: FoundationModules.PaddingParams;
18 | private readonly recipientCipher: FoundationModules.RecipientCipher;
19 |
20 | constructor() {
21 | const foundation = getFoundationModules();
22 | this.paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
23 | this.recipientCipher = new foundation.RecipientCipher();
24 | this.recipientCipher.random = getRandom();
25 | this.recipientCipher.paddingParams = this.paddingParams;
26 | this._isDisposed = false;
27 | this._isFinished = false;
28 | }
29 |
30 | start(privateKey: VirgilPrivateKey) {
31 | this.ensureLegalState();
32 | validatePrivateKey(privateKey);
33 | this.recipientCipher.startDecryptionWithKey(
34 | privateKey.identifier,
35 | privateKey.lowLevelPrivateKey,
36 | new Uint8Array(),
37 | );
38 | }
39 |
40 | update(data: Data) {
41 | this.ensureLegalState();
42 | const myData = dataToUint8Array(data);
43 | const processEncryption = this.recipientCipher.processDecryption(myData);
44 | return toBuffer(processEncryption);
45 | }
46 |
47 | final() {
48 | this.ensureLegalState();
49 | const finishDecryption = this.recipientCipher.finishDecryption();
50 | try {
51 | return toBuffer(finishDecryption);
52 | } finally {
53 | this._isFinished = true;
54 | }
55 | }
56 |
57 | verify(publicKey: VirgilPublicKey, dispose?: boolean): void;
58 | verify(publicKeys: VirgilPublicKey[], dispose?: boolean): void;
59 | verify(arg0: VirgilPublicKey | VirgilPublicKey[], arg1 = true) {
60 | const publicKeys = toArray(arg0);
61 | validatePublicKeysArray(publicKeys);
62 | if (this._isDisposed) {
63 | throw new VirgilCryptoError(
64 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
65 | "Illegal state. Cannot verify signature after the 'dispose' method has been called.",
66 | );
67 | }
68 | if (!this._isFinished) {
69 | throw new VirgilCryptoError(
70 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
71 | "Illegal state. Cannot verify signature before the 'final' method has been called.",
72 | );
73 | }
74 | let signerInfo: FoundationModules.SignerInfo | undefined;
75 | let signerInfoList: FoundationModules.SignerInfoList | undefined;
76 | try {
77 | if (!this.recipientCipher.isDataSigned()) {
78 | throw new VirgilCryptoError(VirgilCryptoErrorStatus.DATA_NOT_SIGNED);
79 | }
80 | signerInfoList = this.recipientCipher.signerInfos();
81 | if (!signerInfoList.hasItem()) {
82 | throw new VirgilCryptoError(VirgilCryptoErrorStatus.DATA_NOT_SIGNED);
83 | }
84 | const signerInfo = signerInfoList.item();
85 | let signerPublicKey: VirgilPublicKey;
86 | for (let i = 0; i < publicKeys.length; i += 1) {
87 | if (NodeBuffer.compare(signerInfo.signerId(), publicKeys[i].identifier) === 0) {
88 | signerPublicKey = publicKeys[i];
89 | break;
90 | }
91 | if (i === publicKeys.length - 1) {
92 | throw new VirgilCryptoError(VirgilCryptoErrorStatus.SIGNER_NOT_FOUND);
93 | }
94 | }
95 | if (!this.recipientCipher.verifySignerInfo(signerInfo, signerPublicKey!.lowLevelPublicKey)) {
96 | throw new VirgilCryptoError(VirgilCryptoErrorStatus.INVALID_SIGNATURE);
97 | }
98 | } finally {
99 | if (signerInfo) {
100 | signerInfo.delete();
101 | }
102 | if (signerInfoList) {
103 | signerInfoList.delete();
104 | }
105 | if (arg1) {
106 | this.dispose();
107 | }
108 | }
109 | }
110 |
111 | dispose() {
112 | this.paddingParams.delete();
113 | this.recipientCipher.delete();
114 | this._isDisposed = true;
115 | }
116 |
117 | private ensureLegalState() {
118 | if (this._isDisposed) {
119 | throw new VirgilCryptoError(
120 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
121 | "Illegal state. Cannot use cipher after the 'dispose' method has been called.",
122 | );
123 | }
124 | if (this._isFinished) {
125 | throw new VirgilCryptoError(
126 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
127 | "Illegal state. Cannot use cipher after the 'final' method has been called.",
128 | );
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilStreamSignAndEncrypt.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer, dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { PADDING_LEN } from './constants';
4 | import { getFoundationModules } from './foundationModules';
5 | import { getRandom } from './globalInstances';
6 | import { FoundationModules, Data } from './types';
7 | import { toArray } from './utils';
8 | import { validatePrivateKey, validatePublicKeysArray } from './validators';
9 | import { VirgilCryptoErrorStatus, VirgilCryptoError } from './VirgilCryptoError';
10 | import { VirgilPrivateKey } from './VirgilPrivateKey';
11 | import { VirgilPublicKey } from './VirgilPublicKey';
12 |
13 | export class VirgilStreamSignAndEncrypt {
14 | private _isRunning: boolean;
15 | private _isFinished: boolean;
16 | private _isDisposed: boolean;
17 |
18 | private readonly recipientCipher: FoundationModules.RecipientCipher;
19 | private readonly aes256Gcm: FoundationModules.Aes256Gcm;
20 | private readonly sha512: FoundationModules.Sha512;
21 | private readonly randomPadding: FoundationModules.RandomPadding | undefined;
22 | private readonly paddingParams: FoundationModules.PaddingParams | undefined;
23 |
24 | get isRunning() {
25 | return this._isRunning;
26 | }
27 |
28 | get isFinished() {
29 | return this._isFinished;
30 | }
31 |
32 | get isDisposed() {
33 | return this._isDisposed;
34 | }
35 |
36 | constructor(arg0: VirgilPrivateKey, arg1: VirgilPublicKey | VirgilPublicKey[], arg2?: boolean) {
37 | validatePrivateKey(arg0);
38 | const publicKeys = toArray(arg1);
39 | validatePublicKeysArray(publicKeys);
40 | const foundation = getFoundationModules();
41 | const random = getRandom();
42 | this.recipientCipher = new foundation.RecipientCipher();
43 | this.aes256Gcm = new foundation.Aes256Gcm();
44 | this.sha512 = new foundation.Sha512();
45 | this.recipientCipher.encryptionCipher = this.aes256Gcm;
46 | this.recipientCipher.random = random;
47 | this.recipientCipher.signerHash = this.sha512;
48 | if (arg2) {
49 | this.randomPadding = new foundation.RandomPadding();
50 | this.randomPadding.random = random;
51 | this.recipientCipher.encryptionPadding = this.randomPadding;
52 | this.paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
53 | this.recipientCipher.paddingParams = this.paddingParams;
54 | }
55 | publicKeys.forEach(publicKey => {
56 | this.recipientCipher.addKeyRecipient(publicKey.identifier, publicKey.lowLevelPublicKey);
57 | });
58 | try {
59 | this.recipientCipher.addSigner(arg0.identifier, arg0.lowLevelPrivateKey);
60 | this._isDisposed = false;
61 | this._isRunning = false;
62 | this._isFinished = false;
63 | } catch (error) {
64 | this.dispose();
65 | throw error;
66 | }
67 | }
68 |
69 | start(length: number) {
70 | this.ensureLegalState();
71 | this.recipientCipher.startSignedEncryption(length);
72 | const messageInfo = this.recipientCipher.packMessageInfo();
73 | this._isRunning = true;
74 | return toBuffer(messageInfo);
75 | }
76 |
77 | update(data: Data) {
78 | this.ensureLegalState();
79 | this.ensureIsRunning();
80 | const myData = dataToUint8Array(data);
81 | const processEncryption = this.recipientCipher.processEncryption(myData);
82 | return toBuffer(processEncryption);
83 | }
84 |
85 | final(dispose = true) {
86 | this.ensureLegalState();
87 | this.ensureIsRunning();
88 | const finishEncryption = this.recipientCipher.finishEncryption();
89 | const messageInfoFooter = this.recipientCipher.packMessageInfoFooter();
90 | try {
91 | return NodeBuffer.concat([finishEncryption, messageInfoFooter]);
92 | } finally {
93 | this._isFinished = true;
94 | this._isRunning = false;
95 | if (dispose) {
96 | this.dispose();
97 | }
98 | }
99 | }
100 |
101 | dispose() {
102 | this.sha512.delete();
103 | this.aes256Gcm.delete();
104 | if (this.randomPadding) {
105 | this.randomPadding.delete();
106 | }
107 | if (this.paddingParams) {
108 | this.paddingParams.delete();
109 | }
110 | this.recipientCipher.delete();
111 | this._isDisposed = true;
112 | }
113 |
114 | private ensureLegalState() {
115 | if (this._isDisposed) {
116 | throw new VirgilCryptoError(
117 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
118 | "Illegal state. Cannot use cipher after the 'dispose' method has been called.",
119 | );
120 | }
121 | if (this._isFinished) {
122 | throw new VirgilCryptoError(
123 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
124 | "Illegal state. Cannot use cipher after the 'final' method has been called.",
125 | );
126 | }
127 | }
128 |
129 | private ensureIsRunning() {
130 | if (!this._isRunning) {
131 | throw new VirgilCryptoError(
132 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
133 | "Illegal state. Cannot use cipher before the 'start' method.",
134 | );
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilStreamSigner.ts:
--------------------------------------------------------------------------------
1 | import { dataToUint8Array, toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { getFoundationModules } from './foundationModules';
4 | import { getRandom } from './globalInstances';
5 | import { Data } from './types';
6 | import { validatePrivateKey } from './validators';
7 | import { VirgilCryptoErrorStatus, VirgilCryptoError } from './VirgilCryptoError';
8 | import { VirgilPrivateKey } from './VirgilPrivateKey';
9 |
10 | export class VirgilStreamSigner {
11 | private _isDisposed = false;
12 |
13 | private readonly signer: FoundationModules.Signer;
14 | private readonly sha512: FoundationModules.Sha512;
15 |
16 | get isDisposed() {
17 | return this._isDisposed;
18 | }
19 |
20 | constructor() {
21 | const foundationModules = getFoundationModules();
22 | this.signer = new foundationModules.Signer();
23 | this.sha512 = new foundationModules.Sha512();
24 | this.signer.hash = this.sha512;
25 | this.signer.random = getRandom();
26 | this.signer.reset();
27 | }
28 |
29 | update(data: Data) {
30 | if (this._isDisposed) {
31 | throw new VirgilCryptoError(
32 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
33 | "Illegal state. Cannot use signer after the 'dispose' method has been called.",
34 | );
35 | }
36 | const myData = dataToUint8Array(data, 'utf8');
37 | this.signer.appendData(myData);
38 | return this;
39 | }
40 |
41 | sign(privateKey: VirgilPrivateKey, final = true) {
42 | if (this._isDisposed) {
43 | throw new VirgilCryptoError(
44 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
45 | "Illegal state. The VirgilStreamSigner has been disposed. Pass 'false' as the second argument to the 'sign' method if you need to generate more than one signature.",
46 | );
47 | }
48 | validatePrivateKey(privateKey);
49 | const result = this.signer.sign(privateKey.lowLevelPrivateKey);
50 | if (final) {
51 | this.dispose();
52 | }
53 | return toBuffer(result);
54 | }
55 |
56 | dispose() {
57 | this.sha512.delete();
58 | this.signer.delete();
59 | this._isDisposed = true;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/VirgilStreamVerifier.ts:
--------------------------------------------------------------------------------
1 | import { dataToUint8Array } from '@virgilsecurity/data-utils';
2 |
3 | import { getFoundationModules } from './foundationModules';
4 | import { Data } from './types';
5 | import { validatePublicKey } from './validators';
6 | import { VirgilCryptoErrorStatus, VirgilCryptoError } from './VirgilCryptoError';
7 | import { VirgilPublicKey } from './VirgilPublicKey';
8 |
9 | export class VirgilStreamVerifier {
10 | private _isDisposed = false;
11 |
12 | private readonly verifier: FoundationModules.Verifier;
13 |
14 | get isDisposed() {
15 | return this._isDisposed;
16 | }
17 |
18 | constructor(signature: Data) {
19 | const foundationModules = getFoundationModules();
20 | const mySignature = dataToUint8Array(signature, 'base64');
21 | this.verifier = new foundationModules.Verifier();
22 | try {
23 | this.verifier.reset(mySignature);
24 | } catch (error) {
25 | this.verifier.delete();
26 | throw error;
27 | }
28 | }
29 |
30 | update(data: Data) {
31 | if (this._isDisposed) {
32 | throw new VirgilCryptoError(
33 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
34 | "Illegal state. Cannot use signer after the 'dispose' method has been called.",
35 | );
36 | }
37 | const myData = dataToUint8Array(data, 'utf8');
38 | this.verifier.appendData(myData);
39 | return this;
40 | }
41 |
42 | verify(publicKey: VirgilPublicKey, final = true) {
43 | if (this._isDisposed) {
44 | throw new VirgilCryptoError(
45 | VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE,
46 | "Illegal state. The VirgilStreamVerifier has been disposed. Pass 'false' as the second argument to the 'verify' method if you need to verify with more than one public key.",
47 | );
48 | }
49 | validatePublicKey(publicKey);
50 | const result = this.verifier.verify(publicKey.lowLevelPublicKey);
51 | if (final) {
52 | this.dispose();
53 | }
54 | return result;
55 | }
56 |
57 | dispose() {
58 | this.verifier.delete();
59 | this._isDisposed = true;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/CryptoCompatibility.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { NodeBuffer } from '@virgilsecurity/data-utils';
4 |
5 | import { initCrypto } from '../foundationModules';
6 | import { VirgilCrypto } from '../VirgilCrypto';
7 | import cryptoCompatibilityData from './crypto_compatibility_data.json';
8 |
9 | // https://github.com/VirgilSecurity/virgil-virgilCrypto-x/blob/master/Tests/VSM002_CryptoCompatibilityTests.swift
10 | describe('CryptoCompatibility', () => {
11 | let virgilCrypto: VirgilCrypto;
12 |
13 | before(async () => {
14 | await initCrypto();
15 | });
16 |
17 | beforeEach(() => {
18 | virgilCrypto = new VirgilCrypto({ useSha256Identifiers: true });
19 | });
20 |
21 | it('test002_DecryptFromSingleRecipient_ShouldDecrypt', () => {
22 | const privateKey = virgilCrypto.importPrivateKey({
23 | value: cryptoCompatibilityData.encrypt_single_recipient.private_key,
24 | encoding: 'base64',
25 | });
26 | const originalData = NodeBuffer.from(
27 | cryptoCompatibilityData.encrypt_single_recipient.original_data,
28 | 'base64',
29 | );
30 | const cipherData = NodeBuffer.from(
31 | cryptoCompatibilityData.encrypt_single_recipient.cipher_data,
32 | 'base64',
33 | );
34 | const decryptedData = virgilCrypto.decrypt(cipherData, privateKey);
35 | expect(decryptedData.equals(originalData)).to.be.true;
36 | });
37 |
38 | it('test003_DecryptFromMultipleRecipients_ShouldDecypt', () => {
39 | const privateKeys = cryptoCompatibilityData.encrypt_multiple_recipients.private_keys.map(
40 | privateKey => virgilCrypto.importPrivateKey({ value: privateKey, encoding: 'base64' }),
41 | );
42 | const originalData = NodeBuffer.from(
43 | cryptoCompatibilityData.encrypt_multiple_recipients.original_data,
44 | 'base64',
45 | );
46 | const cipherData = NodeBuffer.from(
47 | cryptoCompatibilityData.encrypt_multiple_recipients.cipher_data,
48 | 'base64',
49 | );
50 | privateKeys.forEach(privateKey => {
51 | expect(virgilCrypto.decrypt(cipherData, privateKey).equals(originalData)).to.be.true;
52 | });
53 | });
54 |
55 | it('test004_DecryptAndVerifySingleRecipient_ShouldDecryptAndVerify', () => {
56 | const privateKey = virgilCrypto.importPrivateKey({
57 | value: cryptoCompatibilityData.sign_and_encrypt_single_recipient.private_key,
58 | encoding: 'base64',
59 | });
60 | const publicKey = virgilCrypto.extractPublicKey(privateKey);
61 | const originalData = NodeBuffer.from(
62 | cryptoCompatibilityData.sign_and_encrypt_single_recipient.original_data,
63 | 'base64',
64 | );
65 | const cipherData = NodeBuffer.from(
66 | cryptoCompatibilityData.sign_and_encrypt_single_recipient.cipher_data,
67 | 'base64',
68 | );
69 | const decrypted = virgilCrypto.decryptThenVerify(cipherData, privateKey, publicKey);
70 | expect(decrypted.equals(originalData)).to.be.true;
71 | });
72 |
73 | it('test005_DecryptAndVerifyMultipleRecipients_ShouldDecryptAndVerify', () => {
74 | const privateKeys = cryptoCompatibilityData.sign_and_encrypt_multiple_recipients.private_keys.map(
75 | privateKey => virgilCrypto.importPrivateKey({ value: privateKey, encoding: 'base64' }),
76 | );
77 | const originalData = NodeBuffer.from(
78 | cryptoCompatibilityData.sign_and_encrypt_multiple_recipients.original_data,
79 | 'base64',
80 | );
81 | const cipherData = NodeBuffer.from(
82 | cryptoCompatibilityData.sign_and_encrypt_multiple_recipients.cipher_data,
83 | 'base64',
84 | );
85 | const signerPublicKey = virgilCrypto.extractPublicKey(privateKeys[0]);
86 | privateKeys.forEach(privateKey => {
87 | const decrypted = virgilCrypto.decryptThenVerify(cipherData, privateKey, signerPublicKey);
88 | expect(decrypted.equals(originalData)).to.be.true;
89 | });
90 | });
91 |
92 | it('test006_GenerateSignature_ShouldBeEqual', () => {
93 | expect(true).to.be.true;
94 | const privateKey = virgilCrypto.importPrivateKey({
95 | value: cryptoCompatibilityData.generate_signature.private_key,
96 | encoding: 'base64',
97 | });
98 | const originalData = NodeBuffer.from(
99 | cryptoCompatibilityData.generate_signature.original_data,
100 | 'base64',
101 | );
102 | const expectedSignature = NodeBuffer.from(
103 | cryptoCompatibilityData.generate_signature.signature,
104 | 'base64',
105 | );
106 | const signature = virgilCrypto.calculateSignature(originalData, privateKey);
107 | expect(signature.equals(expectedSignature)).to.be.true;
108 | expect(
109 | virgilCrypto.verifySignature(
110 | originalData,
111 | expectedSignature,
112 | virgilCrypto.extractPublicKey(privateKey),
113 | ),
114 | ).to.be.true;
115 | });
116 |
117 | it('test007_DecryptAndVerifyMultipleSigners_ShouldDecryptAndVerify', () => {
118 | const privateKey = virgilCrypto.importPrivateKey({
119 | value: cryptoCompatibilityData.sign_and_encrypt_multiple_signers.private_key,
120 | encoding: 'base64',
121 | });
122 | const publicKeys = cryptoCompatibilityData.sign_and_encrypt_multiple_signers.public_keys.map(
123 | publicKey => virgilCrypto.importPublicKey({ value: publicKey, encoding: 'base64' }),
124 | );
125 | const originalData = NodeBuffer.from(
126 | cryptoCompatibilityData.sign_and_encrypt_multiple_signers.original_data,
127 | 'base64',
128 | );
129 | const cipherData = NodeBuffer.from(
130 | cryptoCompatibilityData.sign_and_encrypt_multiple_signers.cipher_data,
131 | 'base64',
132 | );
133 | const decrypted = virgilCrypto.decryptThenVerify(cipherData, privateKey, publicKeys);
134 | expect(decrypted.equals(originalData)).to.be.true;
135 | });
136 |
137 | it('test008_GenerateEd25519UsingSeed__ShouldMatch', () => {
138 | const seed = NodeBuffer.from(
139 | cryptoCompatibilityData.generate_ed25519_using_seed.seed,
140 | 'base64',
141 | );
142 | const { privateKey, publicKey } = virgilCrypto.generateKeysFromKeyMaterial(seed, 'ED25519');
143 | const expectedPrivateKey = NodeBuffer.from(
144 | cryptoCompatibilityData.generate_ed25519_using_seed.private_key,
145 | 'base64',
146 | );
147 | const expectedPublicKey = NodeBuffer.from(
148 | cryptoCompatibilityData.generate_ed25519_using_seed.public_key,
149 | 'base64',
150 | );
151 | expect(virgilCrypto.exportPrivateKey(privateKey).equals(expectedPrivateKey));
152 | expect(virgilCrypto.exportPublicKey(publicKey).equals(expectedPublicKey));
153 | });
154 |
155 | it('test009_AuthEncrypt__ShouldMatch', () => {
156 | const privateKey1 = virgilCrypto.importPrivateKey({
157 | value: cryptoCompatibilityData.auth_encrypt.private_key1,
158 | encoding: 'base64',
159 | });
160 | const privateKey2 = virgilCrypto.importPrivateKey({
161 | value: cryptoCompatibilityData.auth_encrypt.private_key2,
162 | encoding: 'base64',
163 | });
164 | const publicKey2 = virgilCrypto.extractPublicKey(privateKey2);
165 | const publicKey = virgilCrypto.importPublicKey({
166 | value: cryptoCompatibilityData.auth_encrypt.public_key,
167 | encoding: 'base64',
168 | });
169 | const dataSha512 = NodeBuffer.from(cryptoCompatibilityData.auth_encrypt.data_sha512, 'base64');
170 | const cipherData = NodeBuffer.from(cryptoCompatibilityData.auth_encrypt.cipher_data, 'base64');
171 | const decrypted = virgilCrypto.decryptAndVerify(cipherData, privateKey1, publicKey);
172 | const sha512 = virgilCrypto.calculateHash(decrypted, virgilCrypto.hashAlgorithm.SHA512);
173 | expect(sha512.equals(dataSha512)).to.be.true;
174 | const error1 = () => {
175 | virgilCrypto.decryptAndVerify(cipherData, privateKey2, publicKey);
176 | };
177 | const error2 = () => {
178 | virgilCrypto.decryptAndVerify(cipherData, privateKey1, publicKey2);
179 | };
180 | expect(error1).to.throw;
181 | expect(error2).to.throw;
182 | });
183 |
184 | it('test010_AuthEncryptPQ__ShouldMatch', () => {
185 | const privateKey = virgilCrypto.importPrivateKey({
186 | value: cryptoCompatibilityData.auth_encrypt_pq.private_key,
187 | encoding: 'base64',
188 | });
189 | const publicKey = virgilCrypto.importPublicKey({
190 | value: cryptoCompatibilityData.auth_encrypt_pq.public_key,
191 | encoding: 'base64',
192 | });
193 | const dataSha512 = NodeBuffer.from(
194 | cryptoCompatibilityData.auth_encrypt_pq.data_sha512,
195 | 'base64',
196 | );
197 | const cipherData = NodeBuffer.from(
198 | cryptoCompatibilityData.auth_encrypt_pq.cipher_data,
199 | 'base64',
200 | );
201 | const decrypted = virgilCrypto.decryptAndVerify(cipherData, privateKey, publicKey);
202 | const sha512 = virgilCrypto.calculateHash(decrypted, virgilCrypto.hashAlgorithm.SHA512);
203 | expect(sha512.equals(dataSha512)).to.be.true;
204 | });
205 |
206 | it('test011_AuthEncryptPadding__ShouldMatch', () => {
207 | const privateKey = virgilCrypto.importPrivateKey({
208 | value: cryptoCompatibilityData.auth_encrypt_padding.private_key,
209 | encoding: 'base64',
210 | });
211 | const publicKey = virgilCrypto.importPublicKey({
212 | value: cryptoCompatibilityData.auth_encrypt_padding.public_key,
213 | encoding: 'base64',
214 | });
215 | const dataSha512 = NodeBuffer.from(
216 | cryptoCompatibilityData.auth_encrypt_padding.data_sha512,
217 | 'base64',
218 | );
219 | const cipherData = NodeBuffer.from(
220 | cryptoCompatibilityData.auth_encrypt_padding.cipher_data,
221 | 'base64',
222 | );
223 | const decrypted = virgilCrypto.decryptAndVerify(cipherData, privateKey, publicKey);
224 | const sha512 = virgilCrypto.calculateHash(decrypted, virgilCrypto.hashAlgorithm.SHA512);
225 | expect(sha512.equals(dataSha512)).to.be.true;
226 | });
227 | });
228 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/CryptoFormats.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { NodeBuffer } from '@virgilsecurity/data-utils';
4 |
5 | import { initCrypto } from '../foundationModules';
6 | import { VirgilCrypto } from '../VirgilCrypto';
7 |
8 | // https://github.com/VirgilSecurity/virgil-crypto-x/blob/master/Tests/VSM003_CryptoFormatsTests.swift
9 | describe('CryptoFormats', () => {
10 | let virgilCrypto: VirgilCrypto;
11 |
12 | before(async () => {
13 | await initCrypto();
14 | });
15 |
16 | beforeEach(() => {
17 | virgilCrypto = new VirgilCrypto();
18 | });
19 |
20 | it('test001_SignatureHash', () => {
21 | const { privateKey } = virgilCrypto.generateKeys();
22 | const singature = virgilCrypto.calculateSignature(
23 | { value: 'test', encoding: 'utf8' },
24 | privateKey,
25 | );
26 | const expected = NodeBuffer.from('MFEwDQYJYIZIAWUDBAIDBQA=', 'base64');
27 | expect(expected.compare(singature, 0, 17) === 0).to.be.true;
28 | });
29 |
30 | it('test004_KeyIdentifierIsCorrect', () => {
31 | const keyPair1 = virgilCrypto.generateKeys();
32 | const identifier1 = NodeBuffer.from(keyPair1.privateKey.identifier);
33 | const publicKeyHash1 = virgilCrypto.calculateHash(
34 | virgilCrypto.exportPublicKey(keyPair1.publicKey),
35 | virgilCrypto.hashAlgorithm.SHA512,
36 | );
37 | expect(NodeBuffer.compare(keyPair1.privateKey.identifier, keyPair1.publicKey.identifier) === 0)
38 | .to.be.true;
39 | expect(identifier1.compare(publicKeyHash1, 0, 8) === 0).to.be.true;
40 | const virgilCrypto2 = new VirgilCrypto({ useSha256Identifiers: true });
41 | const keyPair2 = virgilCrypto2.generateKeys();
42 | const publicKeyHash2 = virgilCrypto.calculateHash(
43 | virgilCrypto.exportPublicKey(keyPair2.publicKey),
44 | virgilCrypto.hashAlgorithm.SHA256,
45 | );
46 | expect(publicKeyHash2.equals(keyPair2.privateKey.identifier)).to.be.true;
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilGroupSession.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { NodeBuffer } from '@virgilsecurity/data-utils';
4 |
5 | import { initCrypto } from '../foundationModules';
6 | import { VirgilCrypto } from '../VirgilCrypto';
7 |
8 | describe('group encryption', () => {
9 | let virgilCrypto: VirgilCrypto;
10 |
11 | before(async () => {
12 | await initCrypto();
13 | });
14 |
15 | beforeEach(() => {
16 | virgilCrypto = new VirgilCrypto();
17 | });
18 |
19 | describe('addNewEpoch', () => {
20 | it('adds new epoch message', () => {
21 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
22 | group.addNewEpoch();
23 | group.addNewEpoch();
24 | expect(group.export()).to.have.length(3);
25 | });
26 |
27 | it('increments the currentEpochNumber', () => {
28 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
29 | const oldEpochNumber = group.getCurrentEpochNumber();
30 | group.addNewEpoch();
31 | expect(group.getCurrentEpochNumber()).not.to.equal(oldEpochNumber);
32 | });
33 |
34 | it('returns epochNumber, sessionId and data from epoch message', () => {
35 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
36 | const { epochNumber, sessionId, data } = group.addNewEpoch();
37 | expect(epochNumber).to.equal(group.getCurrentEpochNumber());
38 | expect(sessionId).to.equal(group.getSessionId());
39 | const lastEpochData = group.export().pop();
40 | expect(lastEpochData).not.to.be.undefined;
41 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
42 | expect(lastEpochData!.toString('base64')).to.equal(data);
43 | });
44 | });
45 |
46 | describe('getCurrentEpochNumber', () => {
47 | it('returns zero for new group', () => {
48 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
49 | expect(group.getCurrentEpochNumber()).to.equal(0);
50 | });
51 |
52 | it('increments after adding new epoch', () => {
53 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
54 | group.addNewEpoch();
55 | expect(group.getCurrentEpochNumber()).to.equal(1);
56 | });
57 | });
58 |
59 | describe('parseMessage', () => {
60 | it('returns epochNumber, sessionId and data from encrypted message', () => {
61 | const keypair = virgilCrypto.generateKeys();
62 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
63 | const encrypted = group.encrypt('secret', keypair.privateKey);
64 | const { epochNumber, sessionId, data } = group.parseMessage(encrypted);
65 | expect(epochNumber).to.equal(group.getCurrentEpochNumber());
66 | expect(sessionId).to.equal(group.getSessionId());
67 | expect(encrypted.toString('base64')).to.equal(data);
68 | });
69 | });
70 |
71 | describe('encrypt and decrypt', () => {
72 | it('can encrypt and decrypt data', () => {
73 | const plaintext = 'secret';
74 | const keypair = virgilCrypto.generateKeys();
75 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
76 | const encrypted = group.encrypt(plaintext, keypair.privateKey);
77 | const decrypted = group.decrypt(encrypted, keypair.publicKey);
78 | expect(decrypted.toString('utf8')).to.equal(plaintext);
79 | });
80 |
81 | it('decrypt throws if given a wrong public key', () => {
82 | const plaintext = 'secret';
83 | const keypair1 = virgilCrypto.generateKeys();
84 | const keypair2 = virgilCrypto.generateKeys();
85 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
86 | const encrypted = group.encrypt(plaintext, keypair1.privateKey);
87 | expect(() => group.decrypt(encrypted, keypair2.publicKey)).throws(/Invalid signature/);
88 | });
89 |
90 | it('cannot decrypt data encrypted by another group', () => {
91 | const plaintext = 'secret';
92 | const keypair = virgilCrypto.generateKeys();
93 | const group1 = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
94 | const group2 = virgilCrypto.generateGroupSession(NodeBuffer.from('y'.repeat(10)));
95 | const encrypted = group1.encrypt(plaintext, keypair.privateKey);
96 | expect(() => group2.decrypt(encrypted, keypair.publicKey)).throws(/Session id doesnt match/);
97 | });
98 |
99 | it('can decrypt data from previous epoch', () => {
100 | const plaintext = 'secret';
101 | const keypair = virgilCrypto.generateKeys();
102 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
103 | const encrypted = group.encrypt(plaintext, keypair.privateKey);
104 | group.addNewEpoch();
105 | const decrypted = group.decrypt(encrypted, keypair.publicKey);
106 | expect(decrypted.toString('utf8')).to.equal(plaintext);
107 | });
108 |
109 | it('cannot decrypt data from future epochs', () => {
110 | const plaintext = 'secret';
111 | const keypair = virgilCrypto.generateKeys();
112 |
113 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
114 | const outdatedGroup = virgilCrypto.importGroupSession(group.export());
115 | group.addNewEpoch();
116 | const encrypted = group.encrypt(plaintext, keypair.privateKey);
117 | expect(() => outdatedGroup.decrypt(encrypted, keypair.publicKey)).throws(/Epoch not found/);
118 | });
119 | });
120 |
121 | describe('export', () => {
122 | it('returns current epoch messages as array', () => {
123 | const group = virgilCrypto.generateGroupSession(NodeBuffer.from('x'.repeat(10)));
124 | group.addNewEpoch();
125 | group.addNewEpoch();
126 | group.addNewEpoch();
127 | const epochMessages = group.export();
128 | expect(epochMessages).to.have.length(4); // 1 initial and 3 added manually
129 | });
130 | });
131 | });
132 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilStreamCipher.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { initCrypto } from '../foundationModules';
4 | import { VirgilCrypto } from '../VirgilCrypto';
5 | import { VirgilPublicKey } from '../VirgilPublicKey';
6 |
7 | describe('VirgilStreamCipher', () => {
8 | let virgilCrypto: VirgilCrypto;
9 |
10 | before(async () => {
11 | await initCrypto();
12 | });
13 |
14 | beforeEach(() => {
15 | virgilCrypto = new VirgilCrypto();
16 | });
17 |
18 | it('throws if public keys are invalid', () => {
19 | const error = () => {
20 | virgilCrypto.createStreamCipher({} as VirgilPublicKey);
21 | };
22 | expect(error).to.throw;
23 | });
24 |
25 | it('throws if update is called before start', () => {
26 | const keyPair = virgilCrypto.generateKeys();
27 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
28 | const error = () => {
29 | streamCipher.update({ value: 'data', encoding: 'utf8' });
30 | };
31 | expect(error).to.throw;
32 | streamCipher.dispose();
33 | });
34 |
35 | it('throws if final is called before start', () => {
36 | const keyPair = virgilCrypto.generateKeys();
37 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
38 | const error = () => {
39 | streamCipher.final();
40 | };
41 | expect(error).to.throw;
42 | streamCipher.dispose();
43 | });
44 |
45 | it('throws if update is called after final', () => {
46 | const keyPair = virgilCrypto.generateKeys();
47 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
48 | streamCipher.start();
49 | streamCipher.update({ value: 'data', encoding: 'utf8' });
50 | streamCipher.final();
51 | const error = () => {
52 | streamCipher.update({ value: 'data', encoding: 'utf8' });
53 | };
54 | expect(error).to.throw;
55 | });
56 |
57 | it('throws if start is called after final', () => {
58 | const keyPair = virgilCrypto.generateKeys();
59 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
60 | streamCipher.start();
61 | streamCipher.update({ value: 'data', encoding: 'utf8' });
62 | streamCipher.final();
63 | const error = () => {
64 | streamCipher.start();
65 | };
66 | expect(error).to.throw;
67 | });
68 |
69 | it('throws if final is called after final', () => {
70 | const keyPair = virgilCrypto.generateKeys();
71 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
72 | streamCipher.start();
73 | streamCipher.update({ value: 'data', encoding: 'utf8' });
74 | streamCipher.final();
75 | const error = () => {
76 | streamCipher.final();
77 | };
78 | expect(error).to.throw;
79 | });
80 |
81 | it('throws if start is called after object was disposed', () => {
82 | const keyPair = virgilCrypto.generateKeys();
83 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
84 | streamCipher.dispose();
85 | const error = () => {
86 | streamCipher.start();
87 | };
88 | expect(error).to.throw;
89 | });
90 |
91 | it('throws if update is called after object was disposed', () => {
92 | const keyPair = virgilCrypto.generateKeys();
93 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
94 | streamCipher.dispose();
95 | const error = () => {
96 | streamCipher.update({ value: 'data', encoding: 'utf8' });
97 | };
98 | expect(error).to.throw;
99 | });
100 |
101 | it('throws if final is called after object was disposed', () => {
102 | const keyPair = virgilCrypto.generateKeys();
103 | const streamCipher = virgilCrypto.createStreamCipher(keyPair.publicKey);
104 | streamCipher.dispose();
105 | const error = () => {
106 | streamCipher.final();
107 | };
108 | expect(error).to.throw;
109 | });
110 | });
111 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilStreamDecipher.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { initCrypto } from '../foundationModules';
4 | import { VirgilCrypto } from '../VirgilCrypto';
5 | import { VirgilPrivateKey } from '../VirgilPrivateKey';
6 |
7 | describe('VirgilStreamDecipher', () => {
8 | let virgilCrypto: VirgilCrypto;
9 |
10 | before(async () => {
11 | await initCrypto();
12 | });
13 |
14 | beforeEach(() => {
15 | virgilCrypto = new VirgilCrypto();
16 | });
17 |
18 | it('throws if private key is invalid', () => {
19 | const error = () => {
20 | virgilCrypto.createStreamDecipher({} as VirgilPrivateKey);
21 | };
22 | expect(error).to.throw;
23 | });
24 |
25 | it('throws if update is called after final', () => {
26 | const keyPair = virgilCrypto.generateKeys();
27 | const encrypted = virgilCrypto.encrypt({ value: 'data', encoding: 'utf8' }, keyPair.publicKey);
28 | const streamDecipher = virgilCrypto.createStreamDecipher(keyPair.privateKey);
29 | streamDecipher.update(encrypted);
30 | streamDecipher.final(false);
31 | const error = () => {
32 | streamDecipher.update(encrypted);
33 | };
34 | expect(error).to.throw;
35 | streamDecipher.dispose();
36 | });
37 |
38 | it('throws if final is called after final', () => {
39 | const keyPair = virgilCrypto.generateKeys();
40 | const encrypted = virgilCrypto.encrypt({ value: 'data', encoding: 'utf8' }, keyPair.publicKey);
41 | const streamDecipher = virgilCrypto.createStreamDecipher(keyPair.privateKey);
42 | streamDecipher.update(encrypted);
43 | streamDecipher.final(false);
44 | const error = () => {
45 | streamDecipher.final();
46 | };
47 | expect(error).to.throw;
48 | streamDecipher.dispose();
49 | });
50 |
51 | it('throws if not signed', () => {
52 | const keyPair = virgilCrypto.generateKeys();
53 | const encrypted = virgilCrypto.encrypt({ value: 'data', encoding: 'utf8' }, keyPair.publicKey);
54 | const streamDecipher = virgilCrypto.createStreamDecipher(keyPair.privateKey);
55 | streamDecipher.update(encrypted);
56 | streamDecipher.final(false);
57 | const error = () => {
58 | streamDecipher.getSignature();
59 | };
60 | expect(error).to.throw;
61 | streamDecipher.dispose();
62 | });
63 |
64 | it('throws if update is called after object was disposed', () => {
65 | const keyPair = virgilCrypto.generateKeys();
66 | const encrypted = virgilCrypto.encrypt({ value: 'data', encoding: 'utf8' }, keyPair.publicKey);
67 | const streamDecipher = virgilCrypto.createStreamDecipher(keyPair.privateKey);
68 | streamDecipher.dispose();
69 | const error = () => {
70 | streamDecipher.update(encrypted);
71 | };
72 | expect(error).to.throw;
73 | });
74 |
75 | it('throws if final is called after object was disposed', () => {
76 | const keyPair = virgilCrypto.generateKeys();
77 | const streamDecipher = virgilCrypto.createStreamDecipher(keyPair.privateKey);
78 | streamDecipher.dispose();
79 | const error = () => {
80 | streamDecipher.final();
81 | };
82 | expect(error).to.throw;
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilStreamDecryptAndVerify.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { NodeBuffer } from '@virgilsecurity/data-utils';
4 |
5 | import { initCrypto } from '../foundationModules';
6 | import { NodeBuffer as BufferType } from '../types';
7 | import { VirgilCrypto } from '../VirgilCrypto';
8 |
9 | describe('VirgilStreamDecryptAndVerify', () => {
10 | let virgilCrypto: VirgilCrypto;
11 |
12 | before(async () => {
13 | await initCrypto();
14 | });
15 |
16 | beforeEach(() => {
17 | virgilCrypto = new VirgilCrypto();
18 | });
19 |
20 | it('works', () => {
21 | const data = NodeBuffer.from('data', 'utf8');
22 | const keyPair1 = virgilCrypto.generateKeys();
23 | const keyPair2 = virgilCrypto.generateKeys();
24 | const keyPair3 = virgilCrypto.generateKeys();
25 | const encryptedData = virgilCrypto.signAndEncrypt(data, keyPair1.privateKey, [
26 | keyPair1.publicKey,
27 | keyPair2.publicKey,
28 | ]);
29 | const stream = virgilCrypto.createStreamDecryptAndVerify();
30 | const buffers = new Array();
31 | stream.start(keyPair1.privateKey);
32 | buffers.push(stream.update(encryptedData));
33 | buffers.push(stream.final());
34 | const decrypted = NodeBuffer.concat(buffers);
35 | const notAnError = () => {
36 | stream.verify([keyPair1.publicKey, keyPair2.publicKey], false);
37 | };
38 | const error = () => {
39 | stream.verify(keyPair3.publicKey);
40 | };
41 | expect(decrypted.equals(data)).to.be.true;
42 | expect(notAnError).not.to.throw;
43 | expect(error).to.throw;
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilStreamSignAndEncrypt.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { NodeBuffer } from '@virgilsecurity/data-utils';
4 |
5 | import { initCrypto } from '../foundationModules';
6 | import { NodeBuffer as BufferType } from '../types';
7 | import { VirgilCrypto } from '../VirgilCrypto';
8 |
9 | describe('VirgilStreamSignAndEncrypt', () => {
10 | let virgilCrypto: VirgilCrypto;
11 |
12 | before(async () => {
13 | await initCrypto();
14 | });
15 |
16 | beforeEach(() => {
17 | virgilCrypto = new VirgilCrypto();
18 | });
19 |
20 | it('works', () => {
21 | const data = NodeBuffer.from('data', 'utf8');
22 | const keyPair1 = virgilCrypto.generateKeys();
23 | const keyPair2 = virgilCrypto.generateKeys();
24 | const keyPair3 = virgilCrypto.generateKeys();
25 | const stream = virgilCrypto.createStreamSignAndEncrypt(
26 | keyPair1.privateKey,
27 | [keyPair1.publicKey, keyPair2.publicKey],
28 | true,
29 | );
30 | const buffers = new Array();
31 | buffers.push(stream.start(data.length));
32 | buffers.push(stream.update(data));
33 | buffers.push(stream.final(true));
34 | const encryptedData = NodeBuffer.concat(buffers);
35 | const decryptedData = virgilCrypto.decryptAndVerify(encryptedData, keyPair2.privateKey, [
36 | keyPair1.publicKey,
37 | keyPair2.publicKey,
38 | ]);
39 | const error1 = () => {
40 | virgilCrypto.decryptAndVerify(encryptedData, keyPair3.privateKey, [
41 | keyPair1.publicKey,
42 | keyPair2.publicKey,
43 | ]);
44 | };
45 | const error2 = () => {
46 | virgilCrypto.decryptAndVerify(encryptedData, keyPair2.privateKey, keyPair3.publicKey);
47 | };
48 | expect(decryptedData.equals(data)).to.be.true;
49 | expect(error1).to.throw;
50 | expect(error2).to.throw;
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilStreamSigner.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { initCrypto } from '../foundationModules';
4 | import { VirgilCrypto } from '../VirgilCrypto';
5 |
6 | describe('VirgilStreamSigner', () => {
7 | let virgilCrypto: VirgilCrypto;
8 |
9 | before(async () => {
10 | await initCrypto();
11 | });
12 |
13 | beforeEach(() => {
14 | virgilCrypto = new VirgilCrypto();
15 | });
16 |
17 | it('throws if sign is called more than once by default', () => {
18 | const streamSigner = virgilCrypto.createStreamSigner();
19 | const keyPair1 = virgilCrypto.generateKeys();
20 | const keyPair2 = virgilCrypto.generateKeys();
21 | streamSigner.update({ value: 'data', encoding: 'utf8' });
22 | streamSigner.sign(keyPair1.privateKey);
23 | const error = () => {
24 | streamSigner.sign(keyPair2.privateKey);
25 | };
26 | expect(error).to.throw;
27 | });
28 |
29 | it('sign can be called more than once if `final` is `false`', () => {
30 | const streamSigner = virgilCrypto.createStreamSigner();
31 | const keyPair1 = virgilCrypto.generateKeys();
32 | const keyPair2 = virgilCrypto.generateKeys();
33 | streamSigner.update({ value: 'data', encoding: 'utf8' });
34 | streamSigner.sign(keyPair1.privateKey, false);
35 | const error = () => {
36 | streamSigner.sign(keyPair2.privateKey);
37 | };
38 | expect(error).not.to.throw;
39 | streamSigner.dispose();
40 | });
41 |
42 | it('throws if update is called after object was disposed', () => {
43 | const streamSigner = virgilCrypto.createStreamSigner();
44 | streamSigner.dispose();
45 | const error = () => {
46 | streamSigner.update({ value: 'data', encoding: 'utf8' });
47 | };
48 | expect(error).to.throw;
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/VirgilStreamVerifier.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { NodeBuffer } from '@virgilsecurity/data-utils';
4 |
5 | import { initCrypto } from '../foundationModules';
6 | import { VirgilCrypto } from '../VirgilCrypto';
7 |
8 | describe('VrigilStreamVerifier', () => {
9 | let virgilCrypto: VirgilCrypto;
10 |
11 | before(async () => {
12 | await initCrypto();
13 | });
14 |
15 | beforeEach(() => {
16 | virgilCrypto = new VirgilCrypto();
17 | });
18 |
19 | it('throws if signature is invalid', () => {
20 | const error = () => {
21 | virgilCrypto.createStreamVerifier((undefined as unknown) as Uint8Array);
22 | };
23 | expect(error).to.throw;
24 | });
25 |
26 | it('throws if verify is called more than once by default', () => {
27 | const keyPair = virgilCrypto.generateKeys();
28 | const data = NodeBuffer.from('data');
29 | const signature = virgilCrypto.calculateSignature(data, keyPair.privateKey);
30 | const streamVerifier = virgilCrypto.createStreamVerifier(signature);
31 | streamVerifier.update(data);
32 | streamVerifier.verify(keyPair.publicKey);
33 | const error = () => {
34 | streamVerifier.verify(keyPair.publicKey);
35 | };
36 | expect(error).to.throw;
37 | });
38 |
39 | it('verify can be called more that once if `final` is `false`', () => {
40 | const keyPair = virgilCrypto.generateKeys();
41 | const data = NodeBuffer.from('data');
42 | const signature = virgilCrypto.calculateSignature(data, keyPair.privateKey);
43 | const streamVerifier = virgilCrypto.createStreamVerifier(signature);
44 | streamVerifier.update(data);
45 | streamVerifier.verify(keyPair.publicKey, false);
46 | const error = () => {
47 | streamVerifier.verify(keyPair.publicKey);
48 | };
49 | expect(error).not.to.throw;
50 | });
51 |
52 | it('throws if update is called after object was disposed', () => {
53 | const keyPair = virgilCrypto.generateKeys();
54 | const data = NodeBuffer.from('data');
55 | const signature = virgilCrypto.calculateSignature(data, keyPair.privateKey);
56 | const streamVerifier = virgilCrypto.createStreamVerifier(signature);
57 | streamVerifier.dispose();
58 | const error = () => {
59 | streamVerifier.update(data);
60 | };
61 | expect(error).to.throw;
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/compatibility.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import initWasmFoundation from '@virgilsecurity/core-foundation';
4 | import initAsmjsFoundation from '@virgilsecurity/core-foundation/node.asmjs.cjs';
5 |
6 | import { setFoundationModules } from '../foundationModules';
7 | import { VirgilCrypto } from '../VirgilCrypto';
8 |
9 | describe('compatibility', () => {
10 | let wasmFoundationModules: typeof FoundationModules;
11 | let asmjsFoundationModules: typeof FoundationModules;
12 |
13 | before(async () => {
14 | await Promise.all([initWasmFoundation(), initAsmjsFoundation()]).then(
15 | ([wasmModules, asmjsModules]) => {
16 | wasmFoundationModules = wasmModules;
17 | asmjsFoundationModules = asmjsModules;
18 | },
19 | );
20 | });
21 |
22 | it('encrypts with WebAssembly and decrypts with asm.js', () => {
23 | const data = 'data';
24 |
25 | setFoundationModules(wasmFoundationModules);
26 | const wasmVirgilCrypto = new VirgilCrypto();
27 | const keyPair = wasmVirgilCrypto.generateKeys();
28 | const exportedPrivateKey = wasmVirgilCrypto.exportPrivateKey(keyPair.privateKey);
29 | const encryptedData = wasmVirgilCrypto.encrypt(
30 | { value: data, encoding: 'utf8' },
31 | keyPair.publicKey,
32 | );
33 |
34 | setFoundationModules(asmjsFoundationModules);
35 | const asmjsVirgilCrypto = new VirgilCrypto();
36 | const privateKey = asmjsVirgilCrypto.importPrivateKey(exportedPrivateKey);
37 | const decryptedData = asmjsVirgilCrypto.decrypt(encryptedData, privateKey);
38 | expect(decryptedData.toString()).to.equal(data);
39 | });
40 |
41 | it('encrypts with asm.js and decrypts with WebAssembly', () => {
42 | const data = 'data';
43 |
44 | setFoundationModules(asmjsFoundationModules);
45 | const asmjsVirgilCrypto = new VirgilCrypto();
46 | const keyPair = asmjsVirgilCrypto.generateKeys();
47 | const exportedPrivateKey = asmjsVirgilCrypto.exportPrivateKey(keyPair.privateKey);
48 | const encryptedData = asmjsVirgilCrypto.encrypt(
49 | { value: data, encoding: 'utf8' },
50 | keyPair.publicKey,
51 | );
52 |
53 | setFoundationModules(wasmFoundationModules);
54 | const wasmVirgilCrypto = new VirgilCrypto();
55 | const privateKey = wasmVirgilCrypto.importPrivateKey(exportedPrivateKey);
56 | const decryptedData = wasmVirgilCrypto.decrypt(encryptedData, privateKey);
57 | expect(decryptedData.toString()).to.equal(data);
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/testData.txt:
--------------------------------------------------------------------------------
1 | Hello, Bob!
2 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/__tests__/validators.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 |
3 | import { MIN_GROUP_ID_BYTE_LENGTH } from '../constants';
4 | import { initCrypto } from '../foundationModules';
5 | import {
6 | validatePrivateKey,
7 | validatePublicKey,
8 | validatePublicKeysArray,
9 | validatePositiveNonZeroNumber,
10 | validateGroupId,
11 | } from '../validators';
12 | import { VirgilCrypto } from '../VirgilCrypto';
13 |
14 | describe('validators', () => {
15 | let virgilCrypto: VirgilCrypto;
16 |
17 | before(async () => {
18 | await initCrypto();
19 | });
20 |
21 | beforeEach(() => {
22 | virgilCrypto = new VirgilCrypto();
23 | });
24 |
25 | describe('validatePrivateKey', () => {
26 | it('returns if argument is instance of VirgilPrivateKey class', () => {
27 | const { privateKey } = virgilCrypto.generateKeys();
28 | const func = () => {
29 | validatePrivateKey(privateKey);
30 | };
31 | expect(func).not.to.throw(TypeError);
32 | });
33 |
34 | it('throws if argument is not an instance of VirgilPrivateKey class', () => {
35 | const { publicKey } = virgilCrypto.generateKeys();
36 | const error = () => {
37 | validatePrivateKey(publicKey);
38 | };
39 | expect(error).to.throw(TypeError);
40 | });
41 |
42 | it('throws if VirgilPrivateKey instance was disposed', () => {
43 | const { privateKey } = virgilCrypto.generateKeys();
44 | privateKey.dispose();
45 | const error = () => {
46 | validatePrivateKey(privateKey);
47 | };
48 | expect(error).to.throw(TypeError);
49 | });
50 | });
51 |
52 | describe('validatePublicKey', () => {
53 | it('returns if argument is instance of VirgilPublicKey class', () => {
54 | const { publicKey } = virgilCrypto.generateKeys();
55 | const func = () => {
56 | validatePublicKey(publicKey);
57 | };
58 | expect(func).not.to.throw(TypeError);
59 | });
60 |
61 | it('throws if argument is not an instance of VirgilPublicKey class', () => {
62 | const { privateKey } = virgilCrypto.generateKeys();
63 | const error = () => {
64 | validatePublicKey(privateKey);
65 | };
66 | expect(error).to.throw(TypeError);
67 | });
68 |
69 | it('throws if VirgilPrivateKey instance was disposed', () => {
70 | const { publicKey } = virgilCrypto.generateKeys();
71 | publicKey.dispose();
72 | const error = () => {
73 | validatePublicKey(publicKey);
74 | };
75 | expect(error).to.throw(TypeError);
76 | });
77 | });
78 |
79 | describe('validatePublicKeysArray', () => {
80 | it('returns if argument is an array of VirgilPublicKey instances', () => {
81 | const { publicKey: publicKey1 } = virgilCrypto.generateKeys();
82 | const { publicKey: publicKey2 } = virgilCrypto.generateKeys();
83 | const func = () => {
84 | validatePublicKeysArray([publicKey1, publicKey2]);
85 | };
86 | expect(func).not.to.throw(TypeError);
87 | });
88 |
89 | it('throws if argument is not an array of VirgilPublicKey instances', () => {
90 | const { publicKey } = virgilCrypto.generateKeys();
91 | const { privateKey } = virgilCrypto.generateKeys();
92 | const error = () => {
93 | validatePublicKeysArray([publicKey, privateKey]);
94 | };
95 | expect(error).to.throw(TypeError);
96 | });
97 |
98 | it('throws if array of VirgilPublicKey instances is emtpy', () => {
99 | const error = () => {
100 | validatePublicKeysArray([]);
101 | };
102 | expect(error).to.throw(TypeError);
103 | });
104 |
105 | it('throws if disposed', () => {
106 | const { publicKey: publicKey1 } = virgilCrypto.generateKeys();
107 | const { publicKey: publicKey2 } = virgilCrypto.generateKeys();
108 | publicKey2.dispose();
109 | const error = () => {
110 | validatePublicKeysArray([publicKey1, publicKey2]);
111 | };
112 | expect(error).to.throw(TypeError);
113 | });
114 | });
115 |
116 | describe('validatePositiveNonZeroNumber', () => {
117 | it('returns if argument is number', () => {
118 | const func = () => {
119 | validatePositiveNonZeroNumber(777);
120 | };
121 | expect(func).not.to.throw(TypeError);
122 | });
123 |
124 | it('throws if arugment is not a number', () => {
125 | const error = () => {
126 | validatePositiveNonZeroNumber({});
127 | };
128 | expect(error).to.throw(TypeError);
129 | });
130 |
131 | it('throws if argument is less or equal to 0', () => {
132 | const error = () => {
133 | validatePositiveNonZeroNumber(0);
134 | };
135 | expect(error).to.throw(TypeError);
136 | });
137 | });
138 |
139 | describe('validateGroupId', () => {
140 | it('returns if argument is instance of Uint8Array class and has proper byte length', () => {
141 | const func = () => {
142 | validateGroupId(new Uint8Array(MIN_GROUP_ID_BYTE_LENGTH));
143 | };
144 | expect(func).not.to.throw;
145 | });
146 |
147 | it('throws if argument is not an instance of Uint8Array class', () => {
148 | const error = () => {
149 | validateGroupId({});
150 | };
151 | expect(error).to.throw(TypeError);
152 | });
153 |
154 | it("throws if argument's byte length is too small", () => {
155 | const error = () => {
156 | validateGroupId(new Uint8Array(MIN_GROUP_ID_BYTE_LENGTH - 1));
157 | };
158 | expect(error).to.throw(TypeError);
159 | });
160 | });
161 | });
162 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/constants.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer } from '@virgilsecurity/data-utils';
2 |
3 | export const DATA_SIGNATURE_KEY = NodeBuffer.from('VIRGIL-DATA-SIGNATURE', 'utf8');
4 |
5 | export const DATA_SIGNER_ID_KEY = NodeBuffer.from('VIRGIL-DATA-SIGNER-ID', 'utf8');
6 |
7 | export const PADDING_LEN = 160;
8 |
9 | export const MIN_GROUP_ID_BYTE_LENGTH = 10;
10 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/foundationModules.ts:
--------------------------------------------------------------------------------
1 | import initFoundationModules from '@virgilsecurity/core-foundation';
2 | import { ModuleInitializer } from '@virgilsecurity/init-utils';
3 |
4 | import { createGlobalInstances, resetGlobalInstances } from './globalInstances';
5 | import { FoundationModules } from './types';
6 |
7 | export const moduleInitializer = new ModuleInitializer();
8 | const FOUNDATION_MODULE_KEY = 'foundation';
9 |
10 | moduleInitializer.addModule(FOUNDATION_MODULE_KEY, initFoundationModules);
11 |
12 | moduleInitializer.on('load', (name, modules) => {
13 | if (name === FOUNDATION_MODULE_KEY) {
14 | resetGlobalInstances();
15 | createGlobalInstances(modules);
16 | }
17 | });
18 |
19 | moduleInitializer.on('remove', name => {
20 | if (name === FOUNDATION_MODULE_KEY) {
21 | resetGlobalInstances();
22 | }
23 | });
24 |
25 | export const hasFoundationModules = () => moduleInitializer.hasModule(FOUNDATION_MODULE_KEY);
26 |
27 | export const getFoundationModules = () =>
28 | moduleInitializer.getModule(FOUNDATION_MODULE_KEY);
29 |
30 | export const setFoundationModules = (foundationModules: FoundationModules) => {
31 | moduleInitializer.setModule(FOUNDATION_MODULE_KEY, foundationModules);
32 | };
33 |
34 | export const initCrypto = moduleInitializer.loadModules;
35 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/globalInstances.ts:
--------------------------------------------------------------------------------
1 | import { FoundationModules } from './types';
2 |
3 | let random: FoundationModules.CtrDrbg | undefined;
4 | let keyProvider: FoundationModules.KeyProvider | undefined;
5 |
6 | const ensureExist = () => {
7 | if (!random || !keyProvider) {
8 | throw new Error(
9 | "Cannot use global instances if the 'resetGlobalInstances' function has been called or 'createGlobalInstances' function has not been called yet.",
10 | );
11 | }
12 | };
13 |
14 | export const getRandom = () => {
15 | ensureExist();
16 | return random!;
17 | };
18 |
19 | export const getKeyProvider = () => {
20 | ensureExist();
21 | return keyProvider!;
22 | };
23 |
24 | export const createGlobalInstances = (foundationModules: FoundationModules) => {
25 | random = new foundationModules.CtrDrbg();
26 | try {
27 | random.setupDefaults();
28 | } catch (error) {
29 | random.delete();
30 | throw error;
31 | }
32 | keyProvider = new foundationModules.KeyProvider();
33 | keyProvider.random = random;
34 | try {
35 | keyProvider.setupDefaults();
36 | } catch (error) {
37 | random.delete();
38 | keyProvider.delete();
39 | throw error;
40 | }
41 | };
42 |
43 | export const resetGlobalInstances = () => {
44 | if (!random && !keyProvider) {
45 | return;
46 | }
47 | ensureExist();
48 | random!.delete();
49 | keyProvider!.delete();
50 | random = undefined;
51 | keyProvider = undefined;
52 | };
53 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/groups/createVirgilGroupSession.ts:
--------------------------------------------------------------------------------
1 | import { toBuffer, dataToUint8Array } from '@virgilsecurity/data-utils';
2 |
3 | import { getFoundationModules } from '../foundationModules';
4 | import { FoundationModules, Data, IGroupSession } from '../types';
5 | import { validatePrivateKey, validatePublicKey } from '../validators';
6 | import { VirgilPrivateKey } from '../VirgilPrivateKey';
7 | import { VirgilPublicKey } from '../VirgilPublicKey';
8 | import {
9 | createLowLevelSession,
10 | getEpochNumberFromEpochMessage,
11 | parseGroupSessionMessage,
12 | } from './helpers';
13 |
14 | export function createVirgilGroupSession(epochMessages: Uint8Array[]): IGroupSession {
15 | epochMessages = epochMessages
16 | .slice()
17 | .sort((a, b) => getEpochNumberFromEpochMessage(a) - getEpochNumberFromEpochMessage(b));
18 |
19 | return {
20 | getSessionId() {
21 | const session = createLowLevelSession(epochMessages);
22 | const id = session.getSessionId();
23 | session.delete();
24 | return toBuffer(id).toString('hex');
25 | },
26 |
27 | getCurrentEpochNumber() {
28 | return getEpochNumberFromEpochMessage(epochMessages[epochMessages.length - 1]);
29 | },
30 |
31 | encrypt(data: Data, signingPrivateKey: VirgilPrivateKey) {
32 | const dataBytes = dataToUint8Array(data, 'utf8');
33 | validatePrivateKey(signingPrivateKey);
34 | let session: FoundationModules.GroupSession | undefined;
35 |
36 | try {
37 | session = createLowLevelSession(epochMessages);
38 | const message = session.encrypt(dataBytes, signingPrivateKey.lowLevelPrivateKey);
39 | const encrypted = message.serialize();
40 | message.delete();
41 | return toBuffer(encrypted);
42 | } finally {
43 | session && session.delete();
44 | }
45 | },
46 |
47 | decrypt(encryptedData: Data, verifyingPublicKey: VirgilPublicKey) {
48 | const encryptedDataBytes = dataToUint8Array(encryptedData, 'base64');
49 | validatePublicKey(verifyingPublicKey);
50 | let session: FoundationModules.GroupSession | undefined;
51 | let message: FoundationModules.GroupSessionMessage | undefined;
52 |
53 | try {
54 | session = createLowLevelSession(epochMessages);
55 | message = getFoundationModules().GroupSessionMessage.deserialize(encryptedDataBytes);
56 | return toBuffer(session.decrypt(message, verifyingPublicKey.lowLevelPublicKey));
57 | } finally {
58 | message && message.delete();
59 | session && session.delete();
60 | }
61 | },
62 |
63 | addNewEpoch() {
64 | const session = createLowLevelSession(epochMessages);
65 | try {
66 | const newEpochTicket = session.createGroupTicket();
67 | const newEpoch = newEpochTicket.getTicketMessage();
68 | const newEpochMessage = newEpoch.serialize();
69 |
70 | epochMessages.push(newEpochMessage);
71 |
72 | newEpoch.delete();
73 | newEpochTicket.delete();
74 |
75 | return parseGroupSessionMessage(newEpochMessage);
76 | } finally {
77 | session.delete();
78 | }
79 | },
80 |
81 | export() {
82 | return epochMessages.map(toBuffer);
83 | },
84 |
85 | parseMessage(messageData: Data) {
86 | const messageBytes = dataToUint8Array(messageData, 'base64');
87 | return parseGroupSessionMessage(messageBytes);
88 | },
89 | };
90 | }
91 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/groups/helpers.ts:
--------------------------------------------------------------------------------
1 | import { toBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { getFoundationModules } from '../foundationModules';
4 | import { getRandom } from '../globalInstances';
5 | import { FoundationModules, IGroupSessionMessageInfo } from '../types';
6 |
7 | export function parseGroupSessionMessage(messageData: Uint8Array): IGroupSessionMessageInfo {
8 | const message = getFoundationModules().GroupSessionMessage.deserialize(messageData);
9 | const info: IGroupSessionMessageInfo = {
10 | epochNumber: message.getEpoch(),
11 | sessionId: toBuffer(message.getSessionId()).toString('hex'),
12 | data: toBuffer(messageData).toString('base64'),
13 | };
14 | message.delete();
15 | return info;
16 | }
17 |
18 | export function getEpochNumberFromEpochMessage(epochMessageData: Uint8Array) {
19 | const epoch = getFoundationModules().GroupSessionMessage.deserialize(epochMessageData);
20 | const epochNumber = epoch.getEpoch();
21 | epoch.delete();
22 | return epochNumber;
23 | }
24 |
25 | export function createLowLevelSession(epochMessages: Uint8Array[]) {
26 | const module = getFoundationModules();
27 | const session = new module.GroupSession();
28 | session.rng = getRandom();
29 |
30 | const deleteQueue: FoundationModules.FoundationObject[] = [];
31 | try {
32 | for (const epochMessageData of epochMessages) {
33 | const epoch = getFoundationModules().GroupSessionMessage.deserialize(epochMessageData);
34 | deleteQueue.push(epoch);
35 | session.addEpoch(epoch);
36 | }
37 | return session;
38 | } finally {
39 | while (deleteQueue.length) {
40 | const obj = deleteQueue.pop();
41 | obj && obj.delete();
42 | }
43 | }
44 | }
45 |
46 | export function computeSessionId(groupId: Uint8Array) {
47 | const foundation = getFoundationModules();
48 | const sha512 = new foundation.Sha512();
49 | try {
50 | return sha512.hash(groupId).subarray(0, 32);
51 | } finally {
52 | sha512.delete();
53 | }
54 | }
55 |
56 | export function createInitialEpoch(sessionId: Uint8Array) {
57 | const foundation = getFoundationModules();
58 | const ticket = new foundation.GroupSessionTicket();
59 | ticket.rng = getRandom();
60 | try {
61 | ticket.setupTicketAsNew(sessionId);
62 | return ticket.getTicketMessage();
63 | } finally {
64 | ticket.delete();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from '@virgilsecurity/sdk-crypto';
2 | export {
3 | moduleInitializer,
4 | getFoundationModules,
5 | hasFoundationModules,
6 | setFoundationModules,
7 | initCrypto,
8 | } from './foundationModules';
9 | export { HashAlgorithm } from './HashAlgorithm';
10 | export { KeyPairType } from './KeyPairType';
11 | export { VirgilKeyPair } from './types';
12 | export { VirgilCrypto } from './VirgilCrypto';
13 | export * from './VirgilCryptoError';
14 | export { VirgilPrivateKey } from './VirgilPrivateKey';
15 | export { VirgilPublicKey } from './VirgilPublicKey';
16 | export { VirgilStreamCipher } from './VirgilStreamCipher';
17 | export { VirgilStreamDecipher } from './VirgilStreamDecipher';
18 | export { VirgilStreamSigner } from './VirgilStreamSigner';
19 | export { VirgilStreamVerifier } from './VirgilStreamVerifier';
20 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/types.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import { VirgilPrivateKey } from './VirgilPrivateKey';
4 | import { VirgilPublicKey } from './VirgilPublicKey';
5 |
6 | export type FoundationModules = typeof FoundationModules;
7 |
8 | export type NodeBuffer = import('@virgilsecurity/crypto-types').NodeBuffer;
9 | export type Data = import('@virgilsecurity/crypto-types').Data;
10 | export type IPrivateKey = import('@virgilsecurity/crypto-types').IPrivateKey;
11 | export type IPublicKey = import('@virgilsecurity/crypto-types').IPublicKey;
12 | export type IKeyPair = import('@virgilsecurity/crypto-types').IKeyPair;
13 | export type ICrypto = import('@virgilsecurity/crypto-types').ICrypto;
14 | export type IGroupSession = import('@virgilsecurity/crypto-types').IGroupSession;
15 | export type IGroupSessionMessageInfo = import('@virgilsecurity/crypto-types').IGroupSessionMessageInfo;
16 |
17 | export interface VirgilKeyPair extends IKeyPair {
18 | privateKey: VirgilPrivateKey;
19 | publicKey: VirgilPublicKey;
20 | }
21 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/utils.ts:
--------------------------------------------------------------------------------
1 | export const toArray = (val?: T | T[]): T[] => {
2 | return val == null ? [] : Array.isArray(val) ? val : [val];
3 | };
4 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/src/validators.ts:
--------------------------------------------------------------------------------
1 | import { NodeBuffer } from '@virgilsecurity/data-utils';
2 |
3 | import { MIN_GROUP_ID_BYTE_LENGTH } from './constants';
4 | import { VirgilPrivateKey } from './VirgilPrivateKey';
5 | import { VirgilPublicKey } from './VirgilPublicKey';
6 |
7 | export function validatePrivateKey(privateKey: any) {
8 | if (!(privateKey instanceof VirgilPrivateKey)) {
9 | throw new TypeError("An argument is not an instance of 'VirgilPrivateKey' class.");
10 | }
11 | if (privateKey.isDisposed) {
12 | throw new TypeError(
13 | "Cannot use an instance of 'VirgilPrivateKey' class after it was disposed.",
14 | );
15 | }
16 | }
17 |
18 | export function validatePublicKey(publicKey: any) {
19 | if (!(publicKey instanceof VirgilPublicKey)) {
20 | throw new TypeError("An argument is not a 'VirgilPublicKey'.");
21 | }
22 | if (publicKey.isDisposed) {
23 | throw new TypeError("Cannot use an instance of 'VirgilPublicKey' class after it was disposed.");
24 | }
25 | }
26 |
27 | export function validatePublicKeysArray(publicKeys: any) {
28 | if (!Array.isArray(publicKeys)) {
29 | throw new TypeError('An argument is not an array.');
30 | }
31 | if (!publicKeys.length) {
32 | throw new TypeError("An array of 'VirgilPublicKey' instances should not be empty.");
33 | }
34 | publicKeys.forEach(validatePublicKey);
35 | }
36 |
37 | export function validatePositiveNonZeroNumber(number: any) {
38 | if (typeof number !== 'number') {
39 | throw new TypeError('An argument is not a number.');
40 | }
41 | if (number <= 0) {
42 | throw new TypeError(`An argument should be greater that '0', but received '${number}'.`);
43 | }
44 | }
45 |
46 | export function validateGroupId(groupId: any) {
47 | if (!(groupId instanceof Uint8Array)) {
48 | throw new TypeError("An argument is not an instance of 'Uint8Array' class.");
49 | }
50 | if (groupId.byteLength < MIN_GROUP_ID_BYTE_LENGTH) {
51 | throw new TypeError(
52 | `An argument byte length is too small. Expected to be at least '${MIN_GROUP_ID_BYTE_LENGTH}' bytes.`,
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "declaration": true,
5 | "outDir": "dist",
6 | "declarationDir": "dist/types",
7 | "rootDir": "src",
8 | "esModuleInterop": true,
9 | "moduleResolution": "node",
10 | "resolveJsonModule": true,
11 | "strict": true,
12 | "target": "es2015"
13 | },
14 | "exclude": ["**/*.test.ts", "dist"]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/worker.cjs.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/worker.cjs.js:
--------------------------------------------------------------------------------
1 | const { initCrypto } = require('./dist/worker.cjs');
2 | const foundationWasm = require('./dist/libfoundation.worker.wasm');
3 |
4 | const defaultOptions = {
5 | foundation: [{ locateFile: () => foundationWasm }],
6 | };
7 |
8 | module.exports = require('./dist/worker.cjs');
9 |
10 | module.exports.initCrypto = options => initCrypto(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/worker.es.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/types';
2 |
--------------------------------------------------------------------------------
/packages/virgil-crypto/worker.es.js:
--------------------------------------------------------------------------------
1 | import { initCrypto as rawInitCrypto } from './dist/worker.es';
2 | import foundationWasm from './dist/libfoundation.worker.wasm';
3 |
4 | export * from './dist/worker.es';
5 |
6 | const defaultOptions = {
7 | foundation: [{ locateFile: () => foundationWasm }],
8 | };
9 |
10 | export const initCrypto = options => rawInitCrypto(options || defaultOptions);
11 |
--------------------------------------------------------------------------------
/utils/build.js:
--------------------------------------------------------------------------------
1 | const FORMAT = {
2 | CJS: 'cjs',
3 | ES: 'es',
4 | UMD: 'umd',
5 | };
6 |
7 | const CRYPTO_TYPE = {
8 | WASM: 'wasm',
9 | ASMJS: 'asmjs',
10 | };
11 |
12 | const TARGET = {
13 | BROWSER: 'browser',
14 | WORKER: 'worker',
15 | NODE: 'node',
16 | };
17 |
18 | const getOutputFilename = (target, cryptoType, format, extension = 'js') =>
19 | `${target}${cryptoType === CRYPTO_TYPE.ASMJS ? '.asmjs' : ''}.${format}.${extension}`;
20 |
21 | const getCryptoEntryPointName = (target, cryptoType, format) => {
22 | const myCryptoType = cryptoType === CRYPTO_TYPE.ASMJS ? '.asmjs' : '';
23 | const myFormat = format === FORMAT.UMD ? 'es' : format;
24 | return `${target}${myCryptoType}.${myFormat}.js`;
25 | };
26 |
27 | module.exports = {
28 | FORMAT,
29 | CRYPTO_TYPE,
30 | TARGET,
31 | getOutputFilename,
32 | getCryptoEntryPointName,
33 | };
34 |
--------------------------------------------------------------------------------
/utils/declaration.d.ts.template:
--------------------------------------------------------------------------------
1 | export * from './types';
2 |
--------------------------------------------------------------------------------
/utils/rollup-common-configs.js:
--------------------------------------------------------------------------------
1 | const copy = require('rollup-plugin-copy');
2 | const { getOutputFilename } = require('./build');
3 | const declarationTemplatePath = require.resolve('./declaration.d.ts.template');
4 |
5 | const createDeclarationForInnerEntry = (target, cryptoType, format, outputDir) =>
6 | copy({
7 | targets: [
8 | {
9 | src: declarationTemplatePath,
10 | dest: outputDir,
11 | rename: getOutputFilename(target, cryptoType, format, 'd.ts'),
12 | },
13 | ],
14 | });
15 |
16 | module.exports = {
17 | createDeclarationForInnerEntry,
18 | };
19 |
--------------------------------------------------------------------------------