mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-07-18 06:12:02 +00:00
Compare commits
294 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b07978dbea | ||
|
0cc270dc4a | ||
|
b28c232e22 | ||
|
04a4e81317 | ||
|
29df292338 | ||
|
253cca2799 | ||
|
afcffc8115 | ||
|
a0f387aeab | ||
|
8b3dc56dc2 | ||
|
7888afada6 | ||
|
7273739f04 | ||
|
609297be65 | ||
|
89a297793d | ||
|
32fae9b505 | ||
|
c2dd0a535d | ||
|
2f18a077b4 | ||
|
4aa77a6b12 | ||
|
210dd27479 | ||
|
437a76fbe3 | ||
|
75d250c876 | ||
|
e761427153 | ||
|
90d51ee8c7 | ||
|
ccda21fe91 | ||
|
206999ce11 | ||
|
3272688489 | ||
|
456a365378 | ||
|
42bd594068 | ||
|
ab12e6f068 | ||
|
6bbf12c169 | ||
|
a68fc2e98d | ||
|
d73a0ca52e | ||
|
1b0fac84a8 | ||
|
efaafa9c06 | ||
|
88b3018c9c | ||
|
9aacb478c4 | ||
|
269d169f7c | ||
|
c956d1ad2a | ||
|
9b4231eb75 | ||
|
fdab19b7d9 | ||
|
35f196ea4d | ||
|
d3601fa936 | ||
|
f01e3812e9 | ||
|
00477e3bcb | ||
|
0f4c533dfa | ||
|
d566e7ef3b | ||
|
78e2ddd2bd | ||
|
0ad513887a | ||
|
e7468d830d | ||
|
ae109d46f7 | ||
|
41c9cd1691 | ||
|
3e88839c2b | ||
|
cc2094975b | ||
|
ad4bf3b357 | ||
|
730d762717 | ||
|
e01977c5a3 | ||
|
89901f7097 | ||
|
9894c34f94 | ||
|
e36a9f6b79 | ||
|
b5d94ecae7 | ||
|
1f9c2ddadb | ||
|
d6d06a8404 | ||
|
8b8d0c1510 | ||
|
b998f63aec | ||
|
adc6eb478c | ||
|
2c1bac5ce9 | ||
|
027a5a9332 | ||
|
2c294b56ab | ||
|
487cd076fb | ||
|
b8e2414420 | ||
|
9f747a173f | ||
|
34c5f5c8f0 | ||
|
a008bc2fcb | ||
|
b68060388f | ||
|
afe94ded6b | ||
|
a5e05603ef | ||
|
0b686d363c | ||
|
2d15e717e4 | ||
|
6775dbf670 | ||
|
4b09aae8ca | ||
|
764d8bff3e | ||
|
26b6217041 | ||
|
5500ac4a6e | ||
|
d675670ed9 | ||
|
ad7107233e | ||
|
a521cd9b11 | ||
|
ed670209ad | ||
|
1974eb92be | ||
|
fbd42385e3 | ||
|
9f01868c6c | ||
|
3bb84514d1 | ||
|
5cd0e8cc1a | ||
|
3f131d4a0a | ||
|
0ffe31821a | ||
|
7b3625888c | ||
|
b7bce77ad5 | ||
|
c1f867bd9c | ||
|
e3f02eb6f1 | ||
|
a0874389a9 | ||
|
ce22cf13f0 | ||
|
5fc391c8e0 | ||
|
53a2b590a9 | ||
|
f4dbd62e49 | ||
|
567d68c855 | ||
|
af782c5906 | ||
|
f0593c9e6d | ||
|
8d8294dc3f | ||
|
3a8bab9f44 | ||
|
c983edfdb9 | ||
|
6c9928abd6 | ||
|
720246f012 | ||
|
cfdcbe08d4 | ||
|
df23d634c5 | ||
|
88e1bcf75f | ||
|
c54ea206f0 | ||
|
857d2bd902 | ||
|
200110cb9d | ||
|
9e5778694c | ||
|
87e8f1c86f | ||
|
df75980a88 | ||
|
934390acd3 | ||
|
8b80b46667 | ||
|
e8efad546f | ||
|
e8cbf13d85 | ||
|
c7e0409c1c | ||
|
f4c00893ad | ||
|
b05e77f375 | ||
|
1602c440ad | ||
|
937cc76714 | ||
|
ad478454d8 | ||
|
8c69ffb20f | ||
|
e689a402a3 | ||
|
4bd032a6ae | ||
|
50c61ba46e | ||
|
3a90f70350 | ||
|
743c69524c | ||
|
1a347fa04c | ||
|
71339e08e7 | ||
|
0ab2c2d2d6 | ||
|
cdcca5f828 | ||
|
651d08f67e | ||
|
f2b67f7d82 | ||
|
2c0dc706b7 | ||
|
21d4c8b74e | ||
|
285b6ca392 | ||
|
7d96dd3243 | ||
|
b3421284f9 | ||
|
f3cb8ced36 | ||
|
0a6f63dce5 | ||
|
0ce5f34a08 | ||
|
a826968e71 | ||
|
7608fdd858 | ||
|
bf9b532067 | ||
|
5296f8a42f | ||
|
3a91ae2ed8 | ||
|
e7c11a8e01 | ||
|
9bb96dc2bf | ||
|
957fdd37e9 | ||
|
83257bc4bd | ||
|
cb7fae7fcc | ||
|
7669847c17 | ||
|
dc2793f138 | ||
|
e0b916ace9 | ||
|
0a71af7b89 | ||
|
46adafb207 | ||
|
9e977c7d44 | ||
|
f20267b962 | ||
|
98b285a840 | ||
|
ce5fb8c1b9 | ||
|
0dcf1a6f52 | ||
|
1b6a070fa8 | ||
|
1471e07bf9 | ||
|
bc554d1407 | ||
|
83d2d52205 | ||
|
301c779f49 | ||
|
d552fd423a | ||
|
8401154102 | ||
|
306504c386 | ||
|
bf80e8e511 | ||
|
4e619e60f5 | ||
|
838ecdbaef | ||
|
d14c11310e | ||
|
41c03a86a5 | ||
|
a958f52a5c | ||
|
dfc476c4f6 | ||
|
71eb33a44f | ||
|
310733726e | ||
|
1013becd66 | ||
|
c21454c4e8 | ||
|
4ee48a737a | ||
|
0efc94bd20 | ||
|
68f4b5f496 | ||
|
2f8e234044 | ||
|
363cda56da | ||
|
c2c6fde394 | ||
|
14dde32177 | ||
|
5bc30297de | ||
|
a5ad8cf444 | ||
|
be64372a5e | ||
|
2b0b7abd78 | ||
|
17f2065d21 | ||
|
2f065167fa | ||
|
e0ecce18ce | ||
|
cea1140ec6 | ||
|
e5b7c1f622 | ||
|
20326199d9 | ||
|
4e56e1724f | ||
|
d8b0c74ec9 | ||
|
647fab7170 | ||
|
e66383137f | ||
|
7d63f698c0 | ||
|
a49df7786c | ||
|
c73adb00cc | ||
|
638ea963e6 | ||
|
35abf8fcb4 | ||
|
9430e7f91e | ||
|
8a95de4700 | ||
|
c35a65133f | ||
|
4eb4aa05de | ||
|
21f96a4eb7 | ||
|
39b5124526 | ||
|
93e50dde10 | ||
|
e383da5d44 | ||
|
9b687f380c | ||
|
82abede64a | ||
|
42678bba30 | ||
|
f637ff2485 | ||
|
a56ab406e4 | ||
|
d753941c6e | ||
|
6022eb0838 | ||
|
4c2d42984d | ||
|
de8b16b00b | ||
|
73b8b39de5 | ||
|
288c9cff8f | ||
|
418a0885ad | ||
|
4c744d3b60 | ||
|
4c36aeba17 | ||
|
1c6d0912cd | ||
|
e18804c31e | ||
|
133a2c8833 | ||
|
fad0865b2b | ||
|
4edef07182 | ||
|
19c6ce7c06 | ||
|
3fa76a874f | ||
|
6e0fd6f257 | ||
|
c91d9b61c8 | ||
|
76eeb5aa18 | ||
|
843b5e33d6 | ||
|
308ac7cd1a | ||
|
6c8f978ea4 | ||
|
b93b410357 | ||
|
99a5245fa3 | ||
|
34856d58ab | ||
|
d59c6af7c0 | ||
|
1683bf1dc8 | ||
|
a4edf8b99b | ||
|
27524354af | ||
|
a1f054ca8e | ||
|
5c61c89391 | ||
|
e57e4ffa0d | ||
|
c138a04d2d | ||
|
7c913c0769 | ||
|
1a2d468369 | ||
|
98bc0bbc5f | ||
|
c45bdf602e | ||
|
e92bab1736 | ||
|
c57d1e4d4f | ||
|
04682acd86 | ||
|
fba4833aef | ||
|
2842df7944 | ||
|
74c0d28f86 | ||
|
cf7ed6fa49 | ||
|
c1ffa41697 | ||
|
933119445f | ||
|
a4e6f9dd83 | ||
|
e252db300c | ||
|
98b37d49c4 | ||
|
f979fcd3c2 | ||
|
0af48bbebc | ||
|
3f9d8d557c | ||
|
91a3b50ac9 | ||
|
148d16ab25 | ||
|
6d15450438 | ||
|
ebe1cecdeb | ||
|
904cfb27bd | ||
|
7790beb207 | ||
|
6308461f0f | ||
|
95a0f1f0c2 | ||
|
0c64122342 | ||
|
ce5044b4d7 | ||
|
1daf429a74 | ||
|
22e95bc8a4 | ||
|
9994023490 | ||
|
393fa17512 | ||
|
3cc26d167f |
3
.aegir.js
Normal file
3
.aegir.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
bundlesize: { maxSize: '124kB' }
|
||||||
|
}
|
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,6 +1,11 @@
|
|||||||
|
docs
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
**/node_modules/
|
**/node_modules/
|
||||||
**/*.log
|
**/*.log
|
||||||
test/repo-tests*
|
test/repo-tests*
|
||||||
|
**/bundle.js
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
@@ -31,4 +36,12 @@ build
|
|||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
lib
|
||||||
dist
|
dist
|
||||||
|
test/test-data/go-ipfs-repo/LOCK
|
||||||
|
test/test-data/go-ipfs-repo/LOG
|
||||||
|
test/test-data/go-ipfs-repo/LOG.old
|
||||||
|
|
||||||
|
# while testing npm5
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
34
.npmignore
34
.npmignore
@@ -1,34 +0,0 @@
|
|||||||
**/node_modules/
|
|
||||||
**/*.log
|
|
||||||
test/repo-tests*
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
build
|
|
||||||
|
|
||||||
# Dependency directory
|
|
||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
|
||||||
node_modules
|
|
||||||
|
|
||||||
test
|
|
71
.travis.yml
71
.travis.yml
@@ -1,38 +1,45 @@
|
|||||||
sudo: false
|
|
||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
matrix:
|
cache: npm
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- check
|
||||||
|
- test
|
||||||
|
- cov
|
||||||
|
|
||||||
|
node_js:
|
||||||
|
- '10'
|
||||||
|
- '12'
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
- windows
|
||||||
|
|
||||||
|
script: npx nyc -s npm run test:node -- --bail
|
||||||
|
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
|
||||||
|
|
||||||
|
jobs:
|
||||||
include:
|
include:
|
||||||
- node_js: 4
|
- stage: check
|
||||||
env: CXX=g++-4.8
|
script:
|
||||||
- node_js: 6
|
- npx aegir build --bundlesize
|
||||||
env:
|
- npx aegir dep-check
|
||||||
- SAUCE=true
|
- npm run lint
|
||||||
- CXX=g++-4.8
|
|
||||||
- node_js: stable
|
|
||||||
env: CXX=g++-4.8
|
|
||||||
|
|
||||||
# Make sure we have new NPM.
|
- stage: test
|
||||||
before_install:
|
name: chrome
|
||||||
- npm install -g npm
|
addons:
|
||||||
|
chrome: stable
|
||||||
|
script:
|
||||||
|
- npx aegir test -t browser
|
||||||
|
|
||||||
script:
|
- stage: test
|
||||||
- npm run lint
|
name: firefox
|
||||||
- npm test
|
addons:
|
||||||
- npm run coverage
|
firefox: latest
|
||||||
|
script:
|
||||||
|
- npx aegir test -t browser -- --browsers FirefoxHeadless
|
||||||
|
|
||||||
|
notifications:
|
||||||
before_script:
|
email: false
|
||||||
- export DISPLAY=:99.0
|
|
||||||
- sh -e /etc/init.d/xvfb start
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- npm run coverage-publish
|
|
||||||
|
|
||||||
addons:
|
|
||||||
firefox: 'latest'
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
packages:
|
|
||||||
- g++-4.8
|
|
||||||
|
382
CHANGELOG.md
Normal file
382
CHANGELOG.md
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
<a name="0.19.0"></a>
|
||||||
|
# [0.19.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.18.0...v0.19.0) (2021-01-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.18.0"></a>
|
||||||
|
# [0.18.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.9...v0.18.0) (2020-08-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* remove rendundant public key ([#181](https://github.com/libp2p/js-libp2p-crypto/issues/181)) ([afcffc8](https://github.com/libp2p/js-libp2p-crypto/commit/afcffc8))
|
||||||
|
* replace node buffers with uint8arrays ([#180](https://github.com/libp2p/js-libp2p-crypto/issues/180)) ([a0f387a](https://github.com/libp2p/js-libp2p-crypto/commit/a0f387a))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* The private ed25519 key will no longer include the redundant public key
|
||||||
|
|
||||||
|
* chore: fix lint
|
||||||
|
* - Where node Buffers were returned, now Uint8Arrays are
|
||||||
|
|
||||||
|
* chore: remove commented code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.9"></a>
|
||||||
|
## [0.17.9](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.8...v0.17.9) (2020-08-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add exporting/importing of non rsa keys in libp2p-key format ([#179](https://github.com/libp2p/js-libp2p-crypto/issues/179)) ([7273739](https://github.com/libp2p/js-libp2p-crypto/commit/7273739))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.8"></a>
|
||||||
|
## [0.17.8](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.7...v0.17.8) (2020-07-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* go ed25519 interop ([2f18a07](https://github.com/libp2p/js-libp2p-crypto/commit/2f18a07))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.7"></a>
|
||||||
|
## [0.17.7](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.6...v0.17.7) (2020-06-09)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.6"></a>
|
||||||
|
## [0.17.6](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.5...v0.17.6) (2020-04-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add buffer and update deps ([#25](https://github.com/libp2p/js-libp2p-crypto/issues/25)) ([35f196e](https://github.com/libp2p/js-libp2p-crypto/commit/35f196e))
|
||||||
|
* **unmarshal:** provide only one arg to callback ([#17](https://github.com/libp2p/js-libp2p-crypto/issues/17)) ([3bb8451](https://github.com/libp2p/js-libp2p-crypto/commit/3bb8451))
|
||||||
|
* circular circular dep -> DI ([0dcf1a6](https://github.com/libp2p/js-libp2p-crypto/commit/0dcf1a6))
|
||||||
|
* update deps and repo setup ([cfdcbe0](https://github.com/libp2p/js-libp2p-crypto/commit/cfdcbe0))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add `id()` method to Secp256k1PrivateKey ([f4dbd62](https://github.com/libp2p/js-libp2p-crypto/commit/f4dbd62))
|
||||||
|
* initial implementation ([4c36aeb](https://github.com/libp2p/js-libp2p-crypto/commit/4c36aeb))
|
||||||
|
* next libp2p-crypto ([#4](https://github.com/libp2p/js-libp2p-crypto/issues/4)) ([4ee48a7](https://github.com/libp2p/js-libp2p-crypto/commit/4ee48a7))
|
||||||
|
* use async await ([#18](https://github.com/libp2p/js-libp2p-crypto/issues/18)) ([1974eb9](https://github.com/libp2p/js-libp2p-crypto/commit/1974eb9))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* Callback support has been dropped in favor of async/await.
|
||||||
|
|
||||||
|
* feat: use async/await
|
||||||
|
|
||||||
|
This PR changes this module to remove callbacks and use async/await. The API is unchanged aside from the obvious removal of the `callback` parameter.
|
||||||
|
|
||||||
|
refs https://github.com/ipfs/js-ipfs/issues/1670
|
||||||
|
|
||||||
|
* fix: use latest multihashing-async as it is all promises now
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.5"></a>
|
||||||
|
## [0.17.5](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.4...v0.17.5) (2020-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.4"></a>
|
||||||
|
## [0.17.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.3...v0.17.4) (2020-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add buffer, cleanup, reduce size ([#170](https://github.com/libp2p/js-libp2p-crypto/issues/170)) ([c956d1a](https://github.com/libp2p/js-libp2p-crypto/commit/c956d1a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.3"></a>
|
||||||
|
## [0.17.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.2...v0.17.3) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* remove asn1.js and use node-forge ([#166](https://github.com/libp2p/js-libp2p-crypto/issues/166)) ([00477e3](https://github.com/libp2p/js-libp2p-crypto/commit/00477e3))
|
||||||
|
* remove jwk2privPem and jwk2pubPem ([#162](https://github.com/libp2p/js-libp2p-crypto/issues/162)) ([cc20949](https://github.com/libp2p/js-libp2p-crypto/commit/cc20949))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* removes unused jwk2pem methods `jwk2pubPem` and `jwk2privPem`. These methods are not being used in any js libp2p modules, so only users referencing these directly will be impacted.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.2"></a>
|
||||||
|
## [0.17.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.1...v0.17.2) (2020-01-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add typescript types + linting/tests ([#161](https://github.com/libp2p/js-libp2p-crypto/issues/161)) ([e01977c](https://github.com/libp2p/js-libp2p-crypto/commit/e01977c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.1"></a>
|
||||||
|
## [0.17.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.0...v0.17.1) (2019-10-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* better error for missing web crypto ([a5e0560](https://github.com/libp2p/js-libp2p-crypto/commit/a5e0560))
|
||||||
|
* browser rsa enc/dec ([b8e2414](https://github.com/libp2p/js-libp2p-crypto/commit/b8e2414))
|
||||||
|
* jwk var naming ([8b8d0c1](https://github.com/libp2p/js-libp2p-crypto/commit/8b8d0c1))
|
||||||
|
* lint ([2c294b5](https://github.com/libp2p/js-libp2p-crypto/commit/2c294b5))
|
||||||
|
* padding error ([2c1bac5](https://github.com/libp2p/js-libp2p-crypto/commit/2c1bac5))
|
||||||
|
* use direct buffers instead of converting to hex ([027a5a9](https://github.com/libp2p/js-libp2p-crypto/commit/027a5a9))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add (rsa)pubKey.encrypt and (rsa)privKey.decrypt ([34c5f5c](https://github.com/libp2p/js-libp2p-crypto/commit/34c5f5c))
|
||||||
|
* browser enc/dec ([9f747a1](https://github.com/libp2p/js-libp2p-crypto/commit/9f747a1))
|
||||||
|
* use forge to convert jwk2forge ([b998f63](https://github.com/libp2p/js-libp2p-crypto/commit/b998f63))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.17.0"></a>
|
||||||
|
# [0.17.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.16.1...v0.17.0) (2019-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **deps:** update to ursa-optiona@0.10 ([26b6217](https://github.com/libp2p/js-libp2p-crypto/commit/26b6217))
|
||||||
|
* fix links in README ([#148](https://github.com/libp2p/js-libp2p-crypto/issues/148)) ([5cd0e8c](https://github.com/libp2p/js-libp2p-crypto/commit/5cd0e8c))
|
||||||
|
* put optional args last for key export ([#154](https://github.com/libp2p/js-libp2p-crypto/issues/154)) ([d675670](https://github.com/libp2p/js-libp2p-crypto/commit/d675670))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* refactor to use async/await ([#131](https://github.com/libp2p/js-libp2p-crypto/issues/131)) ([ad71072](https://github.com/libp2p/js-libp2p-crypto/commit/ad71072))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* key export arguments are now swapped so that the optional format is last
|
||||||
|
* API refactored to use async/await
|
||||||
|
|
||||||
|
feat: WIP use async await
|
||||||
|
fix: passing tests
|
||||||
|
chore: update travis node.js versions
|
||||||
|
fix: skip ursa optional tests on windows
|
||||||
|
fix: benchmarks
|
||||||
|
docs: update docs
|
||||||
|
fix: remove broken and intested private key decrypt
|
||||||
|
chore: update deps
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.16.1"></a>
|
||||||
|
## [0.16.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.16.0...v0.16.1) (2019-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.16.0"></a>
|
||||||
|
# [0.16.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.15.0...v0.16.0) (2019-01-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* clean up, bundle size reduction ([8d8294d](https://github.com/libp2p/js-libp2p-crypto/commit/8d8294d))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* getRandomValues method exported from src/keys/rsa-browser.js and src/keys/rsa.js signature has changed from accepting an array to a number for random byte length
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.15.0"></a>
|
||||||
|
# [0.15.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.14.1...v0.15.0) (2019-01-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* nextTick instead of setImmediate, and fix sync in async ([#136](https://github.com/libp2p/js-libp2p-crypto/issues/136)) ([c54ea20](https://github.com/libp2p/js-libp2p-crypto/commit/c54ea20))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.14.1"></a>
|
||||||
|
## [0.14.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.14.0...v0.14.1) (2018-11-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* dont setimmediate when its not needed ([9e57786](https://github.com/libp2p/js-libp2p-crypto/commit/9e57786))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.14.0"></a>
|
||||||
|
# [0.14.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.13.0...v0.14.0) (2018-09-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* windows build ([c7e0409](https://github.com/libp2p/js-libp2p-crypto/commit/c7e0409))
|
||||||
|
* **lint:** use ~ for ursa-optional version ([e8cbf13](https://github.com/libp2p/js-libp2p-crypto/commit/e8cbf13))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* use ursa-optional for lightning fast key generation ([b05e77f](https://github.com/libp2p/js-libp2p-crypto/commit/b05e77f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.13.0"></a>
|
||||||
|
# [0.13.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.12.1...v0.13.0) (2018-04-05)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.12.1"></a>
|
||||||
|
## [0.12.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.12.0...v0.12.1) (2018-02-12)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.12.0"></a>
|
||||||
|
# [0.12.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.11.0...v0.12.0) (2018-01-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* improve perf ([#117](https://github.com/libp2p/js-libp2p-crypto/issues/117)) ([cdcca5f](https://github.com/libp2p/js-libp2p-crypto/commit/cdcca5f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.11.0"></a>
|
||||||
|
# [0.11.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.4...v0.11.0) (2017-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* key exchange with jsrsasign ([#115](https://github.com/libp2p/js-libp2p-crypto/issues/115)) ([b342128](https://github.com/libp2p/js-libp2p-crypto/commit/b342128))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.10.4"></a>
|
||||||
|
## [0.10.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.3...v0.10.4) (2017-12-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* catch error when unmarshaling instead of crashing ([#113](https://github.com/libp2p/js-libp2p-crypto/issues/113)) ([7608fdd](https://github.com/libp2p/js-libp2p-crypto/commit/7608fdd))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.10.3"></a>
|
||||||
|
## [0.10.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.2...v0.10.3) (2017-09-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* switch protocol-buffers to protons ([#110](https://github.com/libp2p/js-libp2p-crypto/issues/110)) ([3a91ae2](https://github.com/libp2p/js-libp2p-crypto/commit/3a91ae2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.10.2"></a>
|
||||||
|
## [0.10.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.1...v0.10.2) (2017-09-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use regular protocol-buffers until protobufjs is fixed ([#109](https://github.com/libp2p/js-libp2p-crypto/issues/109)) ([957fdd3](https://github.com/libp2p/js-libp2p-crypto/commit/957fdd3))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **deps:** upgrade to aegir@12 and browserify-aes@1.0.8 ([83257bc](https://github.com/libp2p/js-libp2p-crypto/commit/83257bc))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.10.1"></a>
|
||||||
|
## [0.10.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.0...v0.10.1) (2017-09-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* switch to protobufjs ([#107](https://github.com/libp2p/js-libp2p-crypto/issues/107)) ([dc2793f](https://github.com/libp2p/js-libp2p-crypto/commit/dc2793f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.10.0"></a>
|
||||||
|
# [0.10.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.4...v0.10.0) (2017-09-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* p2p addrs situation ([#106](https://github.com/libp2p/js-libp2p-crypto/issues/106)) ([9e977c7](https://github.com/libp2p/js-libp2p-crypto/commit/9e977c7))
|
||||||
|
* skip nextTick in nodeify ([#103](https://github.com/libp2p/js-libp2p-crypto/issues/103)) ([f20267b](https://github.com/libp2p/js-libp2p-crypto/commit/f20267b))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.9.4"></a>
|
||||||
|
## [0.9.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.3...v0.9.4) (2017-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* circular circular dep -> DI ([bc554d1](https://github.com/libp2p/js-libp2p-crypto/commit/bc554d1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.9.3"></a>
|
||||||
|
## [0.9.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.2...v0.9.3) (2017-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.9.2"></a>
|
||||||
|
## [0.9.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.1...v0.9.2) (2017-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.9.1"></a>
|
||||||
|
## [0.9.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.0...v0.9.1) (2017-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.9.0"></a>
|
||||||
|
# [0.9.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.8...v0.9.0) (2017-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.8"></a>
|
||||||
|
## [0.8.8](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.7...v0.8.8) (2017-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **ecdh:** allow base64 to be left-0-padded, needed for JWK format ([be64372](https://github.com/libp2p/js-libp2p-crypto/commit/be64372)), closes [#97](https://github.com/libp2p/js-libp2p-crypto/issues/97)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.7"></a>
|
||||||
|
## [0.8.7](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.6...v0.8.7) (2017-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.6"></a>
|
||||||
|
## [0.8.6](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.5...v0.8.6) (2017-03-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **package:** update tweetnacl to version 1.0.0-rc.1 ([4e56e17](https://github.com/libp2p/js-libp2p-crypto/commit/4e56e17))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **keys:** implement generateKeyPairFromSeed for ed25519 ([e5b7c1f](https://github.com/libp2p/js-libp2p-crypto/commit/e5b7c1f))
|
||||||
|
|
||||||
|
|
||||||
|
|
307
README.md
307
README.md
@@ -1,49 +1,52 @@
|
|||||||
# js-libp2p-crypto
|
# js-libp2p-crypto
|
||||||
|
|
||||||
[](http://ipn.io)
|
[](http://protocol.ai)
|
||||||
[](http://ipfs.io/)
|
[](http://libp2p.io/)
|
||||||
[](http://webchat.freenode.net/?channels=%23ipfs)
|
[](http://webchat.freenode.net/?channels=%23libp2p)
|
||||||
[](https://github.com/RichardLitt/standard-readme)
|
[](https://discuss.libp2p.io)
|
||||||
[](https://coveralls.io/github/libp2p/js-libp2p-crypto?branch=master)
|
[](https://codecov.io/gh/libp2p/js-libp2p-crypto)
|
||||||
[](https://travis-ci.org/libp2p/js-libp2p-crypto)
|
[](https://travis-ci.com/libp2p/js-libp2p-crypto)
|
||||||
[](https://circleci.com/gh/libp2p/js-libp2p-crypto)
|
|
||||||
[](https://david-dm.org/libp2p/js-libp2p-crypto)
|
[](https://david-dm.org/libp2p/js-libp2p-crypto)
|
||||||
[](https://github.com/feross/standard)
|
[](https://github.com/feross/standard)
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
[](https://saucelabs.com/u/ipfs-js-
|
|
||||||
libp2p-crypto)
|
|
||||||
|
|
||||||
> Crypto primitives for libp2p in JavaScript
|
> Crypto primitives for libp2p in JavaScript
|
||||||
|
|
||||||
This repo contains the JavaScript implementation of the crypto primitives
|
This repo contains the JavaScript implementation of the crypto primitives needed for libp2p. This is based on this [go implementation](https://github.com/libp2p/go-libp2p-crypto).
|
||||||
needed for libp2p. This is based on this [go implementation](https://github.com/libp2p/go-libp2p-crypto).
|
|
||||||
|
## Lead Maintainer
|
||||||
|
|
||||||
|
[Jacob Heun](https://github.com/jacobheun/)
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Install](#install)
|
- [js-libp2p-crypto](#js-libp2p-crypto)
|
||||||
- [Usage](#usage)
|
- [Lead Maintainer](#lead-maintainer)
|
||||||
- [Example](#example)
|
- [Table of Contents](#table-of-contents)
|
||||||
- [API](#api)
|
- [Install](#install)
|
||||||
- [`hmac`](#hmac)
|
- [Usage](#usage)
|
||||||
- [`create(hash, secret, callback)`](#createhash-secret-callback)
|
- [Web Crypto API](#web-crypto-api)
|
||||||
- [`digest(data, callback)`](#digestdata-callback)
|
- [API](#api)
|
||||||
- [`aes`](#aes)
|
- [`crypto.aes`](#cryptoaes)
|
||||||
- [`create(key, iv, callback)`](#createkey-iv-callback)
|
- [`crypto.aes.create(key, iv)`](#cryptoaescreatekey-iv)
|
||||||
- [`encrypt(data, callback)`](#encryptdata-callback)
|
- [`decrypt(data)`](#decryptdata)
|
||||||
- [`encrypt(data, callback)`](#encryptdata-callback)
|
- [`encrypt(data)`](#encryptdata)
|
||||||
- [`webcrypto`](#webcrypto)
|
- [`crypto.hmac`](#cryptohmac)
|
||||||
- [`keys`](#keys)
|
- [`crypto.hmac.create(hash, secret)`](#cryptohmaccreatehash-secret)
|
||||||
- [`generateKeyPair(type, bits, callback)`](#generatekeypairtype-bits-callback)
|
- [`digest(data)`](#digestdata)
|
||||||
- [`generateEphemeralKeyPair(curve, callback)`](#generateephemeralkeypaircurve-callback)
|
- [`crypto.keys`](#cryptokeys)
|
||||||
- [`keyStretcher(cipherType, hashType, secret, callback)`](#keystretcherciphertype-hashtype-secret-callback)
|
- [`crypto.keys.generateKeyPair(type, bits)`](#cryptokeysgeneratekeypairtype-bits)
|
||||||
- [`marshalPublicKey(key[, type], callback)`](#marshalpublickeykey-type-callback)
|
- [`crypto.keys.generateEphemeralKeyPair(curve)`](#cryptokeysgenerateephemeralkeypaircurve)
|
||||||
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
|
- [`crypto.keys.keyStretcher(cipherType, hashType, secret)`](#cryptokeyskeystretcherciphertype-hashtype-secret)
|
||||||
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
|
- [`crypto.keys.marshalPublicKey(key, [type])`](#cryptokeysmarshalpublickeykey-type)
|
||||||
- [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback)
|
- [`crypto.keys.unmarshalPublicKey(buf)`](#cryptokeysunmarshalpublickeybuf)
|
||||||
- [Contribute](#contribute)
|
- [`crypto.keys.marshalPrivateKey(key, [type])`](#cryptokeysmarshalprivatekeykey-type)
|
||||||
- [License](#license)
|
- [`crypto.keys.unmarshalPrivateKey(buf)`](#cryptokeysunmarshalprivatekeybuf)
|
||||||
|
- [`crypto.keys.import(encryptedKey, password)`](#cryptokeysimportencryptedkey-password)
|
||||||
|
- [`privateKey.export(password, format)`](#privatekeyexportpassword-format)
|
||||||
|
- [`crypto.randomBytes(number)`](#cryptorandombytesnumber)
|
||||||
|
- [`crypto.pbkdf2(password, salt, iterations, keySize, hash)`](#cryptopbkdf2password-salt-iterations-keysize-hash)
|
||||||
|
- [Contribute](#contribute)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@@ -53,138 +56,250 @@ npm install --save libp2p-crypto
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Example
|
```js
|
||||||
|
const crypto = require('libp2p-crypto')
|
||||||
|
|
||||||
|
// Now available to you:
|
||||||
|
//
|
||||||
|
// crypto.aes
|
||||||
|
// crypto.hmac
|
||||||
|
// crypto.keys
|
||||||
|
// etc.
|
||||||
|
//
|
||||||
|
// See full API details below...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Web Crypto API
|
||||||
|
|
||||||
|
The `libp2p-crypto` library depends on the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) in the browser. Web Crypto is available in all modern browsers, however browsers restrict its usage to [Secure Contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).
|
||||||
|
|
||||||
|
**This means you will not be able to use some `libp2p-crypto` functions in the browser when the page is served over HTTP.** To enable the Web Crypto API and allow `libp2p-crypto` to work fully, please serve your page over HTTPS.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### `crypto.aes`
|
||||||
|
|
||||||
|
Exposes an interface to AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.
|
||||||
|
|
||||||
|
This uses `CTR` mode.
|
||||||
|
|
||||||
|
#### `crypto.aes.create(key, iv)`
|
||||||
|
|
||||||
|
- `key: Uint8Array` The key, if length `16` then `AES 128` is used. For length `32`, `AES 256` is used.
|
||||||
|
- `iv: Uint8Array` Must have length `16`.
|
||||||
|
|
||||||
|
Returns `Promise<{decrypt<Function>, encrypt<Function>}>`
|
||||||
|
|
||||||
|
##### `decrypt(data)`
|
||||||
|
|
||||||
|
- `data: Uint8Array`
|
||||||
|
|
||||||
|
Returns `Promise<Uint8Array>`
|
||||||
|
|
||||||
|
##### `encrypt(data)`
|
||||||
|
|
||||||
|
- `data: Uint8Array`
|
||||||
|
|
||||||
|
Returns `Promise<Uint8Array>`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const crypto = require('libp2p-crypto')
|
const crypto = require('libp2p-crypto')
|
||||||
|
|
||||||
crypto.generateKeyPair('RSA', 2048, (err, key) => {
|
// Setting up Key and IV
|
||||||
})
|
|
||||||
|
// A 16 bytes array, 128 Bits, AES-128 is chosen
|
||||||
|
const key128 = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
|
||||||
|
|
||||||
|
// A 16 bytes array, 128 Bits,
|
||||||
|
const IV = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
|
||||||
|
|
||||||
|
async function main () {
|
||||||
|
const decryptedMessage = 'Hello, world!'
|
||||||
|
|
||||||
|
// Encrypting
|
||||||
|
const cipher = await crypto.aes.create(key128, IV)
|
||||||
|
const encryptedBuffer = await cipher.encrypt(Uint8Array.from(decryptedMessage))
|
||||||
|
console.log(encryptedBuffer)
|
||||||
|
// prints: <Uint8Array 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
|
||||||
|
|
||||||
|
// Decrypting
|
||||||
|
const decipher = await crypto.aes.create(key128, IV)
|
||||||
|
const decryptedBuffer = await cipher.decrypt(encryptedBuffer)
|
||||||
|
|
||||||
|
console.log(decryptedBuffer)
|
||||||
|
// prints: <Uint8Array 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
|
||||||
|
|
||||||
|
console.log(decryptedBuffer.toString('utf-8'))
|
||||||
|
// prints: Hello, world!
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
## API
|
### `crypto.hmac`
|
||||||
|
|
||||||
### `hmac`
|
|
||||||
|
|
||||||
Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198. An HMAC is a cryptographic hash that uses a key to sign a message. The receiver verifies the hash by recomputing it using the same key.
|
Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198. An HMAC is a cryptographic hash that uses a key to sign a message. The receiver verifies the hash by recomputing it using the same key.
|
||||||
|
|
||||||
#### `create(hash, secret, callback)`
|
#### `crypto.hmac.create(hash, secret)`
|
||||||
|
|
||||||
- `hash: String`
|
- `hash: String`
|
||||||
- `secret: Buffer`
|
- `secret: Uint8Array`
|
||||||
- `callback: Function`
|
|
||||||
|
|
||||||
##### `digest(data, callback)`
|
Returns `Promise<{digest<Function>}>`
|
||||||
|
|
||||||
- `data: Buffer`
|
##### `digest(data)`
|
||||||
- `callback: Function`
|
|
||||||
|
|
||||||
### `aes`
|
- `data: Uint8Array`
|
||||||
Expoes an interface to AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.
|
|
||||||
|
|
||||||
This uses `CTR` mode.
|
Returns `Promise<Uint8Array>`
|
||||||
|
|
||||||
#### `create(key, iv, callback)`
|
Example:
|
||||||
|
|
||||||
- `key: Buffer` The key, if length `16` then `AES 128` is used. For length `32`, `AES 256` is used.
|
```js
|
||||||
- `iv: Buffer` Must have length `16`.
|
const crypto = require('libp2p-crypto')
|
||||||
- `callback: Function`
|
|
||||||
|
|
||||||
##### `encrypt(data, callback)`
|
async function main () {
|
||||||
|
const hash = 'SHA1' // 'SHA256' || 'SHA512'
|
||||||
|
const hmac = await crypto.hmac.create(hash, uint8ArrayFromString('secret'))
|
||||||
|
const sig = await hmac.digest(uint8ArrayFromString('hello world'))
|
||||||
|
console.log(sig)
|
||||||
|
}
|
||||||
|
|
||||||
- `data: Buffer`
|
main()
|
||||||
- `callback: Function`
|
```
|
||||||
|
|
||||||
##### `encrypt(data, callback)`
|
### `crypto.keys`
|
||||||
|
|
||||||
- `data: Buffer`
|
**Supported Key Types**
|
||||||
- `callback: Function`
|
|
||||||
|
|
||||||
|
The [`generateKeyPair`](#generatekeypairtype-bits), [`marshalPublicKey`](#marshalpublickeykey-type), and [`marshalPrivateKey`](#marshalprivatekeykey-type) functions accept a string `type` argument.
|
||||||
|
|
||||||
### `webcrypto`
|
Currently the `'RSA'`, `'ed25519'`, and `secp256k1` types are supported, although ed25519 and secp256k1 keys support only signing and verification of messages. For encryption / decryption support, RSA keys should be used.
|
||||||
|
|
||||||
Depending on the environment this is either an instance of [node-webcrypto-ossl](https://github.com/PeculiarVentures/node-webcrypto-ossl) or the result of `window.crypto`.
|
### `crypto.keys.generateKeyPair(type, bits)`
|
||||||
|
|
||||||
### `keys`
|
- `type: String`, see [Supported Key Types](#supported-key-types) above.
|
||||||
|
|
||||||
### `generateKeyPair(type, bits, callback)`
|
|
||||||
|
|
||||||
- `type: String`, only `'RSA'` is currently supported
|
|
||||||
- `bits: Number` Minimum of 1024
|
- `bits: Number` Minimum of 1024
|
||||||
- `callback: Function`
|
|
||||||
|
Returns `Promise<{privateKey<Uint8Array>, publicKey<Uint8Array>}>`
|
||||||
|
|
||||||
Generates a keypair of the given type and bitsize.
|
Generates a keypair of the given type and bitsize.
|
||||||
|
|
||||||
### `generateEphemeralKeyPair(curve, callback)`
|
### `crypto.keys.generateEphemeralKeyPair(curve)`
|
||||||
|
|
||||||
- `curve: String`, one of `'P-256'`, `'P-384'`, `'P-521'` is currently supported
|
- `curve: String`, one of `'P-256'`, `'P-384'`, `'P-521'` is currently supported
|
||||||
- `callback: Function`
|
|
||||||
|
Returns `Promise`
|
||||||
|
|
||||||
Generates an ephemeral public key and returns a function that will compute the shared secret key.
|
Generates an ephemeral public key and returns a function that will compute the shared secret key.
|
||||||
|
|
||||||
Focuses only on ECDH now, but can be made more general in the future.
|
Focuses only on ECDH now, but can be made more general in the future.
|
||||||
|
|
||||||
Calls back with an object of the form
|
Resolves to an object of the form:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
key: Buffer,
|
key: Uint8Array,
|
||||||
genSharedKey: Function
|
genSharedKey: Function
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `keyStretcher(cipherType, hashType, secret, callback)`
|
### `crypto.keys.keyStretcher(cipherType, hashType, secret)`
|
||||||
|
|
||||||
- `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'`
|
- `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'`
|
||||||
- `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512`
|
- `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512`
|
||||||
- `secret: Buffer`
|
- `secret: Uint8Array`
|
||||||
- `callback: Function`
|
|
||||||
|
Returns `Promise`
|
||||||
|
|
||||||
Generates a set of keys for each party by stretching the shared key.
|
Generates a set of keys for each party by stretching the shared key.
|
||||||
|
|
||||||
Calls back with an object of the form
|
Resolves to an object of the form:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
k1: {
|
k1: {
|
||||||
iv: Buffer,
|
iv: Uint8Array,
|
||||||
cipherKey: Buffer,
|
cipherKey: Uint8Array,
|
||||||
macKey: Buffer
|
macKey: Uint8Array
|
||||||
},
|
},
|
||||||
k2: {
|
k2: {
|
||||||
iv: Buffer,
|
iv: Uint8Array,
|
||||||
cipherKey: Buffer,
|
cipherKey: Uint8Array,
|
||||||
macKey: Buffer
|
macKey: Uint8Array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `marshalPublicKey(key[, type], callback)`
|
### `crypto.keys.marshalPublicKey(key, [type])`
|
||||||
|
|
||||||
- `key: crypto.rsa.RsaPublicKey`
|
- `key: keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | keys.secp256k1.Secp256k1PublicKey`
|
||||||
- `type: String`, only `'RSA'` is currently supported
|
- `type: String`, see [Supported Key Types](#supported-key-types) above. Defaults to 'rsa'.
|
||||||
|
|
||||||
|
Returns `Uint8Array`
|
||||||
|
|
||||||
Converts a public key object into a protobuf serialized public key.
|
Converts a public key object into a protobuf serialized public key.
|
||||||
|
|
||||||
### `unmarshalPublicKey(buf)`
|
### `crypto.keys.unmarshalPublicKey(buf)`
|
||||||
|
|
||||||
- `buf: Buffer`
|
- `buf: Uint8Array`
|
||||||
|
|
||||||
Converts a protobuf serialized public key into its representative object.
|
Returns `RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey`
|
||||||
|
|
||||||
### `marshalPrivateKey(key[, type])`
|
Converts a protobuf serialized public key into its representative object.
|
||||||
|
|
||||||
- `key: crypto.rsa.RsaPrivateKey`
|
### `crypto.keys.marshalPrivateKey(key, [type])`
|
||||||
- `type: String`, only `'RSA'` is currently supported
|
|
||||||
|
- `key: keys.rsa.RsaPrivateKey | keys.ed25519.Ed25519PrivateKey | keys.secp256k1.Secp256k1PrivateKey`
|
||||||
|
- `type: String`, see [Supported Key Types](#supported-key-types) above.
|
||||||
|
|
||||||
|
Returns `Uint8Array`
|
||||||
|
|
||||||
Converts a private key object into a protobuf serialized private key.
|
Converts a private key object into a protobuf serialized private key.
|
||||||
|
|
||||||
### `unmarshalPrivateKey(buf, callback)`
|
### `crypto.keys.unmarshalPrivateKey(buf)`
|
||||||
|
|
||||||
- `buf: Buffer`
|
- `buf: Uint8Array`
|
||||||
- `callback: Function`
|
|
||||||
|
Returns `Promise<RsaPrivateKey|Ed25519PrivateKey|Secp256k1PrivateKey>`
|
||||||
|
|
||||||
Converts a protobuf serialized private key into its representative object.
|
Converts a protobuf serialized private key into its representative object.
|
||||||
|
|
||||||
|
### `crypto.keys.import(encryptedKey, password)`
|
||||||
|
|
||||||
|
- `encryptedKey: string`
|
||||||
|
- `password: string`
|
||||||
|
|
||||||
|
Returns `Promise<PrivateKey>`
|
||||||
|
|
||||||
|
Converts an exported private key into its representative object. Supported formats are 'pem' (RSA only) and 'libp2p-key'.
|
||||||
|
|
||||||
|
### `privateKey.export(password, format)`
|
||||||
|
|
||||||
|
- `password: string`
|
||||||
|
- `format: string` the format to export to: 'pem' (rsa only), 'libp2p-key'
|
||||||
|
|
||||||
|
Returns `string`
|
||||||
|
|
||||||
|
Exports the password protected `PrivateKey`. RSA keys will be exported as password protected PEM by default. Ed25519 and Secp256k1 keys will be exported as password protected AES-GCM base64 encoded strings ('libp2p-key' format).
|
||||||
|
|
||||||
|
### `crypto.randomBytes(number)`
|
||||||
|
|
||||||
|
- `number: Number`
|
||||||
|
|
||||||
|
Returns `Uint8Array`
|
||||||
|
|
||||||
|
Generates a Uint8Array with length `number` populated by random bytes.
|
||||||
|
|
||||||
|
### `crypto.pbkdf2(password, salt, iterations, keySize, hash)`
|
||||||
|
|
||||||
|
- `password: String`
|
||||||
|
- `salt: String`
|
||||||
|
- `iterations: Number`
|
||||||
|
- `keySize: Number` in bytes
|
||||||
|
- `hash: String` the hashing algorithm ('sha1', 'sha2-512', ...)
|
||||||
|
|
||||||
|
Computes the Password Based Key Derivation Function 2; returning a new password.
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
@@ -196,4 +311,4 @@ This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/c
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](LICENSE)
|
[MIT](./LICENSE)
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Benchmark = require('benchmark')
|
const Benchmark = require('benchmark')
|
||||||
@@ -9,29 +10,14 @@ const secrets = []
|
|||||||
const curves = ['P-256', 'P-384', 'P-521']
|
const curves = ['P-256', 'P-384', 'P-521']
|
||||||
|
|
||||||
curves.forEach((curve) => {
|
curves.forEach((curve) => {
|
||||||
suite.add(`ephemeral key with secrect ${curve}`, (d) => {
|
suite.add(`ephemeral key with secrect ${curve}`, async (d) => {
|
||||||
crypto.generateEphemeralKeyPair('P-256', (err, res) => {
|
const res = await crypto.keys.generateEphemeralKeyPair('P-256')
|
||||||
if (err) {
|
const secret = await res.genSharedKey(res.key)
|
||||||
throw err
|
secrets.push(secret)
|
||||||
}
|
d.resolve()
|
||||||
res.genSharedKey(res.key, (err, secret) => {
|
}, { defer: true })
|
||||||
if (err) {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
secrets.push(secret)
|
|
||||||
|
|
||||||
d.resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, {
|
|
||||||
defer: true
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
suite
|
suite
|
||||||
.on('cycle', (event) => {
|
.on('cycle', (event) => console.log(String(event.target)))
|
||||||
console.log(String(event.target))
|
.run({ async: true })
|
||||||
})
|
|
||||||
.run({
|
|
||||||
'async': true
|
|
||||||
})
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Benchmark = require('benchmark')
|
const Benchmark = require('benchmark')
|
||||||
|
|
||||||
const crypto = require('../src')
|
const crypto = require('../src')
|
||||||
|
|
||||||
const suite = new Benchmark.Suite('key-stretcher')
|
const suite = new Benchmark.Suite('key-stretcher')
|
||||||
@@ -10,38 +12,23 @@ const keys = []
|
|||||||
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
|
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
|
||||||
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
||||||
|
|
||||||
crypto.generateEphemeralKeyPair('P-256', (err, res) => {
|
;(async () => {
|
||||||
if (err) {
|
const res = await crypto.keys.generateEphemeralKeyPair('P-256')
|
||||||
throw err
|
const secret = await res.genSharedKey(res.key)
|
||||||
}
|
|
||||||
|
|
||||||
res.genSharedKey(res.key, (err, secret) => {
|
ciphers.forEach((cipher) => hashes.forEach((hash) => {
|
||||||
if (err) {
|
setup(cipher, hash, secret)
|
||||||
throw err
|
}))
|
||||||
}
|
|
||||||
ciphers.forEach((cipher) => {
|
|
||||||
hashes.forEach((hash) => {
|
|
||||||
suite.add(`keyStretcher ${cipher} ${hash}`, (d) => {
|
|
||||||
crypto.keyStretcher(cipher, hash, secret, (err, k) => {
|
|
||||||
if (err) {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.push(k)
|
suite
|
||||||
d.resolve()
|
.on('cycle', (event) => console.log(String(event.target)))
|
||||||
})
|
.run({ async: true })
|
||||||
}, {
|
})()
|
||||||
defer: true
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
suite
|
function setup (cipher, hash, secret) {
|
||||||
.on('cycle', (event) => {
|
suite.add(`keyStretcher ${cipher} ${hash}`, async (d) => {
|
||||||
console.log(String(event.target))
|
const k = await crypto.keys.keyStretcher(cipher, hash, secret)
|
||||||
})
|
keys.push(k)
|
||||||
.run({
|
d.resolve()
|
||||||
'async': true
|
}, { defer: true })
|
||||||
})
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Benchmark = require('benchmark')
|
const Benchmark = require('benchmark')
|
||||||
@@ -9,44 +10,28 @@ const keys = []
|
|||||||
const bits = [1024, 2048, 4096]
|
const bits = [1024, 2048, 4096]
|
||||||
|
|
||||||
bits.forEach((bit) => {
|
bits.forEach((bit) => {
|
||||||
suite.add(`generateKeyPair ${bit}bits`, (d) => {
|
suite.add(`generateKeyPair ${bit}bits`, async (d) => {
|
||||||
crypto.generateKeyPair('RSA', bit, (err, key) => {
|
const key = await crypto.keys.generateKeyPair('RSA', bit)
|
||||||
if (err) throw err
|
keys.push(key)
|
||||||
keys.push(key)
|
d.resolve()
|
||||||
d.resolve()
|
|
||||||
})
|
|
||||||
}, {
|
}, {
|
||||||
defer: true
|
defer: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
suite.add('sign and verify', (d) => {
|
suite.add('sign and verify', async (d) => {
|
||||||
const key = keys[0]
|
const key = keys[0]
|
||||||
const text = key.genSecret()
|
const text = key.genSecret()
|
||||||
|
|
||||||
key.sign(text, (err, sig) => {
|
const sig = await key.sign(text)
|
||||||
if (err) {
|
const res = await key.public.verify(text, sig)
|
||||||
throw err
|
|
||||||
}
|
|
||||||
|
|
||||||
key.public.verify(text, sig, (err, res) => {
|
if (res !== true) { throw new Error('failed to verify') }
|
||||||
if (err) {
|
d.resolve()
|
||||||
throw err
|
|
||||||
}
|
|
||||||
if (res !== true) {
|
|
||||||
throw new Error('failed to verify')
|
|
||||||
}
|
|
||||||
d.resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, {
|
}, {
|
||||||
defer: true
|
defer: true
|
||||||
})
|
})
|
||||||
|
|
||||||
suite
|
suite
|
||||||
.on('cycle', (event) => {
|
.on('cycle', (event) => console.log(String(event.target)))
|
||||||
console.log(String(event.target))
|
.run({ async: true })
|
||||||
})
|
|
||||||
.run({
|
|
||||||
'async': true
|
|
||||||
})
|
|
||||||
|
12
circle.yml
12
circle.yml
@@ -1,12 +0,0 @@
|
|||||||
machine:
|
|
||||||
node:
|
|
||||||
version: stable
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
pre:
|
|
||||||
- google-chrome --version
|
|
||||||
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
|
|
||||||
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
|
|
||||||
- sudo apt-get update
|
|
||||||
- sudo apt-get --only-upgrade install google-chrome-stable
|
|
||||||
- google-chrome --version
|
|
113
package.json
113
package.json
@@ -1,69 +1,104 @@
|
|||||||
{
|
{
|
||||||
"name": "libp2p-crypto",
|
"name": "libp2p-crypto",
|
||||||
"version": "0.7.0",
|
"version": "0.19.0",
|
||||||
"description": "Crypto primitives for libp2p",
|
"description": "Crypto primitives for libp2p",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
|
"types": "src/index.d.ts",
|
||||||
|
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||||
"browser": {
|
"browser": {
|
||||||
"node-webcrypto-ossl": false,
|
"./src/aes/ciphers.js": "./src/aes/ciphers-browser.js",
|
||||||
"./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js",
|
"./src/ciphers/aes-gcm.js": "./src/ciphers/aes-gcm.browser.js",
|
||||||
"./src/crypto/hmac.js": "./src/crypto/hmac-browser.js",
|
"./src/hmac/index.js": "./src/hmac/index-browser.js",
|
||||||
"./src/crypto/aes.js": "./src/crypto/aes-browser.js"
|
"./src/keys/ecdh.js": "./src/keys/ecdh-browser.js",
|
||||||
|
"./src/keys/rsa.js": "./src/keys/rsa-browser.js"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"src",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "aegir-lint",
|
"lint": "aegir lint",
|
||||||
"build": "aegir-build",
|
"build": "aegir build",
|
||||||
"test": "aegir-test",
|
"build-proto": "pbjs --wrap commonjs --target static-module src/keys/keys.proto > src/keys/keys.proto.js",
|
||||||
"test:node": "aegir-test --env node",
|
"test": "aegir test",
|
||||||
"test:browser": "aegir-test --env browser",
|
"test:node": "aegir test -t node",
|
||||||
"release": "aegir-release",
|
"test:browser": "aegir test -t browser -t webworker",
|
||||||
"release-minor": "aegir-release --type minor",
|
"release": "aegir release",
|
||||||
"release-major": "aegir-release --type major",
|
"release-minor": "aegir release --type minor",
|
||||||
"coverage": "aegir-coverage",
|
"release-major": "aegir release --type major",
|
||||||
"coverage-publish": "aegir-coverage publish"
|
"coverage": "aegir coverage --ignore src/keys/keys.proto.js",
|
||||||
|
"size": "aegir build --bundlesize",
|
||||||
|
"test:types": "npx tsc"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"IPFS",
|
"IPFS",
|
||||||
"libp2p",
|
"libp2p",
|
||||||
"crypto",
|
"crypto",
|
||||||
"rsa"
|
"rsa",
|
||||||
|
"secp256k1"
|
||||||
],
|
],
|
||||||
"author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asn1.js": "^4.8.1",
|
"err-code": "^2.0.0",
|
||||||
"async": "^2.1.2",
|
"is-typedarray": "^1.0.0",
|
||||||
"multihashing-async": "^0.2.0",
|
"iso-random-stream": "^1.1.0",
|
||||||
"node-webcrypto-ossl": "^1.0.7",
|
"keypair": "^1.0.1",
|
||||||
"nodeify": "^1.0.0",
|
"multibase": "^3.0.0",
|
||||||
"protocol-buffers": "^3.1.6",
|
"multicodec": "^2.0.0",
|
||||||
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
|
"multihashing-async": "^2.0.1",
|
||||||
|
"node-forge": "^0.10.0",
|
||||||
|
"pem-jwk": "^2.0.0",
|
||||||
|
"protons": "^2.0.0",
|
||||||
|
"secp256k1": "^4.0.0",
|
||||||
|
"uint8arrays": "^1.1.0",
|
||||||
|
"ursa-optional": "^0.10.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aegir": "^9.0.1",
|
"@types/chai": "^4.2.12",
|
||||||
"benchmark": "^2.1.2",
|
"@types/chai-string": "^1.4.2",
|
||||||
"chai": "^3.5.0",
|
"@types/dirty-chai": "^2.0.2",
|
||||||
"pre-commit": "^1.1.3"
|
"@types/mocha": "^8.0.1",
|
||||||
|
"aegir": "^25.0.0",
|
||||||
|
"benchmark": "^2.1.4",
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"chai-string": "^1.5.0",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"sinon": "^9.0.0"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
|
||||||
"lint",
|
|
||||||
"test"
|
|
||||||
],
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0.0"
|
"node": ">=10.0.0",
|
||||||
|
"npm": ">=6.0.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ipfs/js-libp2p-crypto.git"
|
"url": "https://github.com/libp2p/js-libp2p-crypto.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/ipfs/js-libp2p-crypto/issues"
|
"url": "https://github.com/libp2p/js-libp2p-crypto/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/ipfs/js-libp2p-crypto",
|
"homepage": "https://github.com/libp2p/js-libp2p-crypto",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"David Dias <daviddias.p@gmail.com>",
|
"David Dias <daviddias.p@gmail.com>",
|
||||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||||
|
"Jacob Heun <jacobheun@gmail.com>",
|
||||||
|
"Maciej Krüger <mkg20001@gmail.com>",
|
||||||
|
"dryajov <dryajov@gmail.com>",
|
||||||
|
"Alan Shaw <alan.shaw@protocol.ai>",
|
||||||
|
"Cayman <caymannava@gmail.com>",
|
||||||
|
"Hugo Dias <hugomrdias@gmail.com>",
|
||||||
|
"Yusef Napora <yusef@napora.org>",
|
||||||
|
"Victor Bjelkholm <victorbjelkholm@gmail.com>",
|
||||||
|
"Vasco Santos <vasco.santos@ua.pt>",
|
||||||
|
"Arve Knudsen <arve.knudsen@gmail.com>",
|
||||||
|
"Alex Potsides <alex@achingbrain.net>",
|
||||||
"Richard Littauer <richard.littauer@gmail.com>",
|
"Richard Littauer <richard.littauer@gmail.com>",
|
||||||
"greenkeeperio-bot <support@greenkeeper.io>",
|
"Richard Schneider <makaretu@gmail.com>",
|
||||||
"nikuda <nikuda@gmail.com>"
|
"Jack Kleeman <jackkleeman@gmail.com>",
|
||||||
|
"nikuda <nikuda@gmail.com>",
|
||||||
|
"dirkmc <dirkmdev@gmail.com>",
|
||||||
|
"Alberto Elias <hi@albertoelias.me>",
|
||||||
|
"Tom Swindell <t.swindell@rubyx.co.uk>",
|
||||||
|
"Carson Farmer <carson.farmer@gmail.com>",
|
||||||
|
"Joao Santos <jrmsantos15@gmail.com>"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
17
src/aes/cipher-mode.js
Normal file
17
src/aes/cipher-mode.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
|
||||||
|
const CIPHER_MODES = {
|
||||||
|
16: 'aes-128-ctr',
|
||||||
|
32: 'aes-256-ctr'
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (key) {
|
||||||
|
const mode = CIPHER_MODES[key.length]
|
||||||
|
if (!mode) {
|
||||||
|
const modes = Object.entries(CIPHER_MODES).map(([k, v]) => `${k} (${v})`).join(' / ')
|
||||||
|
throw errcode(new Error(`Invalid key length ${key.length} bytes. Must be ${modes}`), 'ERR_INVALID_KEY_LENGTH')
|
||||||
|
}
|
||||||
|
return mode
|
||||||
|
}
|
29
src/aes/ciphers-browser.js
Normal file
29
src/aes/ciphers-browser.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
require('node-forge/lib/aes')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createCipheriv: (mode, key, iv) => {
|
||||||
|
const cipher2 = forge.cipher.createCipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
|
||||||
|
cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
|
||||||
|
return {
|
||||||
|
update: (data) => {
|
||||||
|
cipher2.update(forge.util.createBuffer(uint8ArrayToString(data, 'ascii')))
|
||||||
|
return uint8ArrayFromString(cipher2.output.getBytes(), 'ascii')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createDecipheriv: (mode, key, iv) => {
|
||||||
|
const cipher2 = forge.cipher.createDecipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
|
||||||
|
cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
|
||||||
|
return {
|
||||||
|
update: (data) => {
|
||||||
|
cipher2.update(forge.util.createBuffer(uint8ArrayToString(data, 'ascii')))
|
||||||
|
return uint8ArrayFromString(cipher2.output.getBytes(), 'ascii')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/aes/ciphers.js
Normal file
8
src/aes/ciphers.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const crypto = require('crypto')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createCipheriv: crypto.createCipheriv,
|
||||||
|
createDecipheriv: crypto.createDecipheriv
|
||||||
|
}
|
22
src/aes/index.js
Normal file
22
src/aes/index.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const ciphers = require('./ciphers')
|
||||||
|
const cipherMode = require('./cipher-mode')
|
||||||
|
|
||||||
|
exports.create = async function (key, iv) { // eslint-disable-line require-await
|
||||||
|
const mode = cipherMode(key)
|
||||||
|
const cipher = ciphers.createCipheriv(mode, key, iv)
|
||||||
|
const decipher = ciphers.createDecipheriv(mode, key, iv)
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
async encrypt (data) { // eslint-disable-line require-await
|
||||||
|
return cipher.update(data)
|
||||||
|
},
|
||||||
|
|
||||||
|
async decrypt (data) { // eslint-disable-line require-await
|
||||||
|
return decipher.update(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
89
src/ciphers/aes-gcm.browser.js
Normal file
89
src/ciphers/aes-gcm.browser.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const concat = require('uint8arrays/concat')
|
||||||
|
const fromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
const webcrypto = require('../webcrypto')
|
||||||
|
|
||||||
|
// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @param {string} [options.algorithm=AES-GCM]
|
||||||
|
* @param {Number} [options.nonceLength=12]
|
||||||
|
* @param {Number} [options.keyLength=16]
|
||||||
|
* @param {string} [options.digest=sha256]
|
||||||
|
* @param {Number} [options.saltLength=16]
|
||||||
|
* @param {Number} [options.iterations=32767]
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
function create ({
|
||||||
|
algorithm = 'AES-GCM',
|
||||||
|
nonceLength = 12,
|
||||||
|
keyLength = 16,
|
||||||
|
digest = 'SHA-256',
|
||||||
|
saltLength = 16,
|
||||||
|
iterations = 32767
|
||||||
|
} = {}) {
|
||||||
|
const crypto = webcrypto.get()
|
||||||
|
keyLength *= 8 // Browser crypto uses bits instead of bytes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the provided password to derive a pbkdf2 key. The key
|
||||||
|
* will then be used to encrypt the data.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array} data The data to decrypt
|
||||||
|
* @param {string} password A plain password
|
||||||
|
* @returns {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
async function encrypt (data, password) { // eslint-disable-line require-await
|
||||||
|
const salt = crypto.getRandomValues(new Uint8Array(saltLength))
|
||||||
|
const nonce = crypto.getRandomValues(new Uint8Array(nonceLength))
|
||||||
|
const aesGcm = { name: algorithm, iv: nonce }
|
||||||
|
|
||||||
|
// Derive a key using PBKDF2.
|
||||||
|
const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } }
|
||||||
|
const rawKey = await crypto.subtle.importKey('raw', fromString(password), { name: 'PBKDF2' }, false, ['deriveKey', 'deriveBits'])
|
||||||
|
const cryptoKey = await crypto.subtle.deriveKey(deriveParams, rawKey, { name: algorithm, length: keyLength }, true, ['encrypt'])
|
||||||
|
|
||||||
|
// Encrypt the string.
|
||||||
|
const ciphertext = await crypto.subtle.encrypt(aesGcm, cryptoKey, data)
|
||||||
|
return concat([salt, aesGcm.iv, new Uint8Array(ciphertext)])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the provided password to derive a pbkdf2 key. The key
|
||||||
|
* will then be used to decrypt the data. The options used to create
|
||||||
|
* this decryption cipher must be the same as those used to create
|
||||||
|
* the encryption cipher.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array} data The data to decrypt
|
||||||
|
* @param {string} password A plain password
|
||||||
|
* @returns {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
async function decrypt (data, password) {
|
||||||
|
const salt = data.slice(0, saltLength)
|
||||||
|
const nonce = data.slice(saltLength, saltLength + nonceLength)
|
||||||
|
const ciphertext = data.slice(saltLength + nonceLength)
|
||||||
|
const aesGcm = { name: algorithm, iv: nonce }
|
||||||
|
|
||||||
|
// Derive the key using PBKDF2.
|
||||||
|
const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } }
|
||||||
|
const rawKey = await crypto.subtle.importKey('raw', fromString(password), { name: 'PBKDF2' }, false, ['deriveKey', 'deriveBits'])
|
||||||
|
const cryptoKey = await crypto.subtle.deriveKey(deriveParams, rawKey, { name: algorithm, length: keyLength }, true, ['decrypt'])
|
||||||
|
|
||||||
|
// Decrypt the string.
|
||||||
|
const plaintext = await crypto.subtle.decrypt(aesGcm, cryptoKey, ciphertext)
|
||||||
|
return new Uint8Array(plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
encrypt,
|
||||||
|
decrypt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
create
|
||||||
|
}
|
130
src/ciphers/aes-gcm.js
Normal file
130
src/ciphers/aes-gcm.js
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const uint8ArrayConcat = require('uint8arrays/concat')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @param {Number} [options.algorithmTagLength=16]
|
||||||
|
* @param {Number} [options.nonceLength=12]
|
||||||
|
* @param {Number} [options.keyLength=16]
|
||||||
|
* @param {string} [options.digest=sha256]
|
||||||
|
* @param {Number} [options.saltLength=16]
|
||||||
|
* @param {Number} [options.iterations=32767]
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
function create ({
|
||||||
|
algorithmTagLength = 16,
|
||||||
|
nonceLength = 12,
|
||||||
|
keyLength = 16,
|
||||||
|
digest = 'sha256',
|
||||||
|
saltLength = 16,
|
||||||
|
iterations = 32767
|
||||||
|
} = {}) {
|
||||||
|
const algorithm = 'aes-128-gcm'
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Uint8Array} data
|
||||||
|
* @param {Uint8Array} key
|
||||||
|
* @returns {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
async function encryptWithKey (data, key) { // eslint-disable-line require-await
|
||||||
|
const nonce = crypto.randomBytes(nonceLength)
|
||||||
|
|
||||||
|
// Create the cipher instance.
|
||||||
|
const cipher = crypto.createCipheriv(algorithm, key, nonce)
|
||||||
|
|
||||||
|
// Encrypt and prepend nonce.
|
||||||
|
const ciphertext = uint8ArrayConcat([cipher.update(data), cipher.final()])
|
||||||
|
|
||||||
|
return uint8ArrayConcat([nonce, ciphertext, cipher.getAuthTag()])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the provided password to derive a pbkdf2 key. The key
|
||||||
|
* will then be used to encrypt the data.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array} data The data to decrypt
|
||||||
|
* @param {string|Uint8Array} password A plain password
|
||||||
|
* @returns {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
async function encrypt (data, password) { // eslint-disable-line require-await
|
||||||
|
// Generate a 128-bit salt using a CSPRNG.
|
||||||
|
const salt = crypto.randomBytes(saltLength)
|
||||||
|
|
||||||
|
if (typeof password === 'string' || password instanceof String) {
|
||||||
|
password = uint8ArrayFromString(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive a key using PBKDF2.
|
||||||
|
const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest)
|
||||||
|
|
||||||
|
// Encrypt and prepend salt.
|
||||||
|
return uint8ArrayConcat([salt, await encryptWithKey(Uint8Array.from(data), key)])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the given cipher text with the provided key. The `key` should
|
||||||
|
* be a cryptographically safe key and not a plaintext password. To use
|
||||||
|
* a plaintext password, use `decrypt`. The options used to create
|
||||||
|
* this decryption cipher must be the same as those used to create
|
||||||
|
* the encryption cipher.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Uint8Array} ciphertextAndNonce The data to decrypt
|
||||||
|
* @param {Uint8Array} key
|
||||||
|
* @returns {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await
|
||||||
|
// Create Uint8Arrays of nonce, ciphertext and tag.
|
||||||
|
const nonce = ciphertextAndNonce.slice(0, nonceLength)
|
||||||
|
const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength)
|
||||||
|
const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength)
|
||||||
|
|
||||||
|
// Create the cipher instance.
|
||||||
|
const cipher = crypto.createDecipheriv(algorithm, key, nonce)
|
||||||
|
|
||||||
|
// Decrypt and return result.
|
||||||
|
cipher.setAuthTag(tag)
|
||||||
|
return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the provided password to derive a pbkdf2 key. The key
|
||||||
|
* will then be used to decrypt the data. The options used to create
|
||||||
|
* this decryption cipher must be the same as those used to create
|
||||||
|
* the encryption cipher.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array} data The data to decrypt
|
||||||
|
* @param {string|Uint8Array} password A plain password
|
||||||
|
*/
|
||||||
|
async function decrypt (data, password) { // eslint-disable-line require-await
|
||||||
|
// Create Uint8Arrays of salt and ciphertextAndNonce.
|
||||||
|
const salt = data.slice(0, saltLength)
|
||||||
|
const ciphertextAndNonce = data.slice(saltLength)
|
||||||
|
|
||||||
|
if (typeof password === 'string' || password instanceof String) {
|
||||||
|
password = uint8ArrayFromString(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive the key using PBKDF2.
|
||||||
|
const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest)
|
||||||
|
|
||||||
|
// Decrypt and return result.
|
||||||
|
return decryptWithKey(ciphertextAndNonce, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
encrypt,
|
||||||
|
decrypt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
create
|
||||||
|
}
|
@@ -1,7 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
exports.webcrypto = require('./crypto/webcrypto')()
|
|
||||||
exports.hmac = require('./crypto/hmac')
|
|
||||||
exports.ecdh = require('./crypto/ecdh')
|
|
||||||
exports.aes = require('./crypto/aes')
|
|
||||||
exports.rsa = require('./crypto/rsa')
|
|
@@ -1,52 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const nodeify = require('nodeify')
|
|
||||||
|
|
||||||
const crypto = require('./webcrypto')()
|
|
||||||
|
|
||||||
exports.create = function (key, iv, callback) {
|
|
||||||
nodeify(crypto.subtle.importKey(
|
|
||||||
'raw',
|
|
||||||
key,
|
|
||||||
{
|
|
||||||
name: 'AES-CTR'
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['encrypt', 'decrypt']
|
|
||||||
).then((key) => {
|
|
||||||
const counter = copy(iv)
|
|
||||||
|
|
||||||
return {
|
|
||||||
encrypt (data, cb) {
|
|
||||||
nodeify(crypto.subtle.encrypt(
|
|
||||||
{
|
|
||||||
name: 'AES-CTR',
|
|
||||||
counter: counter,
|
|
||||||
length: 128
|
|
||||||
},
|
|
||||||
key,
|
|
||||||
data
|
|
||||||
).then((raw) => Buffer.from(raw)), cb)
|
|
||||||
},
|
|
||||||
|
|
||||||
decrypt (data, cb) {
|
|
||||||
nodeify(crypto.subtle.decrypt(
|
|
||||||
{
|
|
||||||
name: 'AES-CTR',
|
|
||||||
counter: counter,
|
|
||||||
length: 128
|
|
||||||
},
|
|
||||||
key,
|
|
||||||
data
|
|
||||||
).then((raw) => Buffer.from(raw)), cb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
function copy (buf) {
|
|
||||||
const fresh = new Buffer(buf.length)
|
|
||||||
buf.copy(fresh)
|
|
||||||
|
|
||||||
return fresh
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const crypto = require('crypto')
|
|
||||||
|
|
||||||
const ciphers = {
|
|
||||||
16: 'aes-128-ctr',
|
|
||||||
32: 'aes-256-ctr'
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.create = function (key, iv, callback) {
|
|
||||||
const name = ciphers[key.length]
|
|
||||||
if (!name) {
|
|
||||||
return callback(new Error('Invalid key length'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const cipher = crypto.createCipheriv(name, key, iv)
|
|
||||||
const decipher = crypto.createDecipheriv(name, key, iv)
|
|
||||||
|
|
||||||
const res = {
|
|
||||||
encrypt (data, cb) {
|
|
||||||
cb(null, cipher.update(data))
|
|
||||||
},
|
|
||||||
|
|
||||||
decrypt (data, cb) {
|
|
||||||
cb(null, decipher.update(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, res)
|
|
||||||
}
|
|
@@ -1,101 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const crypto = require('./webcrypto')()
|
|
||||||
const nodeify = require('nodeify')
|
|
||||||
const BN = require('asn1.js').bignum
|
|
||||||
|
|
||||||
const util = require('./util')
|
|
||||||
const toBase64 = util.toBase64
|
|
||||||
const toBn = util.toBn
|
|
||||||
|
|
||||||
exports.generateEphmeralKeyPair = function (curve, callback) {
|
|
||||||
nodeify(crypto.subtle.generateKey(
|
|
||||||
{
|
|
||||||
name: 'ECDH',
|
|
||||||
namedCurve: curve
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['deriveBits']
|
|
||||||
).then((pair) => {
|
|
||||||
// forcePrivate is used for testing only
|
|
||||||
const genSharedKey = (theirPub, forcePrivate, cb) => {
|
|
||||||
if (typeof forcePrivate === 'function') {
|
|
||||||
cb = forcePrivate
|
|
||||||
forcePrivate = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const privateKey = forcePrivate || pair.privateKey
|
|
||||||
nodeify(crypto.subtle.importKey(
|
|
||||||
'jwk',
|
|
||||||
unmarshalPublicKey(curve, theirPub),
|
|
||||||
{
|
|
||||||
name: 'ECDH',
|
|
||||||
namedCurve: curve
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
[]
|
|
||||||
).then((publicKey) => {
|
|
||||||
return crypto.subtle.deriveBits(
|
|
||||||
{
|
|
||||||
name: 'ECDH',
|
|
||||||
namedCurve: curve,
|
|
||||||
public: publicKey
|
|
||||||
},
|
|
||||||
privateKey,
|
|
||||||
256
|
|
||||||
)
|
|
||||||
}).then((bits) => {
|
|
||||||
// return p.derive(pub.getPublic()).toBuffer('be')
|
|
||||||
return Buffer.from(bits)
|
|
||||||
}), cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
return crypto.subtle.exportKey(
|
|
||||||
'jwk',
|
|
||||||
pair.publicKey
|
|
||||||
).then((publicKey) => {
|
|
||||||
return {
|
|
||||||
key: marshalPublicKey(publicKey),
|
|
||||||
genSharedKey
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
const curveLengths = {
|
|
||||||
'P-256': 32,
|
|
||||||
'P-384': 48,
|
|
||||||
'P-521': 66
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal converts a jwk encodec ECDH public key into the
|
|
||||||
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
|
|
||||||
// go-ipfs uses)
|
|
||||||
function marshalPublicKey (jwk) {
|
|
||||||
const byteLen = curveLengths[jwk.crv]
|
|
||||||
|
|
||||||
return Buffer.concat([
|
|
||||||
Buffer([4]), // uncompressed point
|
|
||||||
toBn(jwk.x).toBuffer('be', byteLen),
|
|
||||||
toBn(jwk.y).toBuffer('be', byteLen)
|
|
||||||
], 1 + byteLen * 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
|
|
||||||
function unmarshalPublicKey (curve, key) {
|
|
||||||
const byteLen = curveLengths[curve]
|
|
||||||
|
|
||||||
if (!key.slice(0, 1).equals(Buffer([4]))) {
|
|
||||||
throw new Error('Invalid key format')
|
|
||||||
}
|
|
||||||
const x = new BN(key.slice(1, byteLen + 1))
|
|
||||||
const y = new BN(key.slice(1 + byteLen))
|
|
||||||
|
|
||||||
return {
|
|
||||||
kty: 'EC',
|
|
||||||
crv: curve,
|
|
||||||
x: toBase64(x),
|
|
||||||
y: toBase64(y),
|
|
||||||
ext: true
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,38 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const nodeify = require('nodeify')
|
|
||||||
|
|
||||||
const crypto = require('./webcrypto')()
|
|
||||||
const lengths = require('./hmac-lengths')
|
|
||||||
|
|
||||||
const hashTypes = {
|
|
||||||
SHA1: 'SHA-1',
|
|
||||||
SHA256: 'SHA-256',
|
|
||||||
SHA512: 'SHA-512'
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.create = function (hashType, secret, callback) {
|
|
||||||
const hash = hashTypes[hashType]
|
|
||||||
|
|
||||||
nodeify(crypto.subtle.importKey(
|
|
||||||
'raw',
|
|
||||||
secret,
|
|
||||||
{
|
|
||||||
name: 'HMAC',
|
|
||||||
hash: {name: hash}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['sign']
|
|
||||||
).then((key) => {
|
|
||||||
return {
|
|
||||||
digest (data, cb) {
|
|
||||||
nodeify(crypto.subtle.sign(
|
|
||||||
{name: 'HMAC'},
|
|
||||||
key,
|
|
||||||
data
|
|
||||||
).then((raw) => Buffer.from(raw)), cb)
|
|
||||||
},
|
|
||||||
length: lengths[hashType]
|
|
||||||
}
|
|
||||||
}), callback)
|
|
||||||
}
|
|
@@ -1,24 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const crypto = require('crypto')
|
|
||||||
|
|
||||||
const lengths = require('./hmac-lengths')
|
|
||||||
|
|
||||||
exports.create = function (hash, secret, callback) {
|
|
||||||
const res = {
|
|
||||||
digest (data, cb) {
|
|
||||||
const hmac = genFresh()
|
|
||||||
hmac.update(data)
|
|
||||||
|
|
||||||
setImmediate(() => {
|
|
||||||
cb(null, hmac.digest())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
length: lengths[hash]
|
|
||||||
}
|
|
||||||
|
|
||||||
function genFresh () {
|
|
||||||
return crypto.createHmac(hash.toLowerCase(), secret)
|
|
||||||
}
|
|
||||||
callback(null, res)
|
|
||||||
}
|
|
@@ -1,228 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const nodeify = require('nodeify')
|
|
||||||
const asn1 = require('asn1.js')
|
|
||||||
|
|
||||||
const util = require('./util')
|
|
||||||
const toBase64 = util.toBase64
|
|
||||||
const toBn = util.toBn
|
|
||||||
const crypto = require('./webcrypto')()
|
|
||||||
|
|
||||||
exports.generateKey = function (bits, callback) {
|
|
||||||
nodeify(crypto.subtle.generateKey(
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
modulusLength: bits,
|
|
||||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign', 'verify']
|
|
||||||
)
|
|
||||||
.then(exportKey)
|
|
||||||
.then((keys) => ({
|
|
||||||
privateKey: keys[0],
|
|
||||||
publicKey: keys[1]
|
|
||||||
})), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes a jwk key
|
|
||||||
exports.unmarshalPrivateKey = function (key, callback) {
|
|
||||||
const privateKey = crypto.subtle.importKey(
|
|
||||||
'jwk',
|
|
||||||
key,
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign']
|
|
||||||
)
|
|
||||||
|
|
||||||
nodeify(Promise.all([
|
|
||||||
privateKey,
|
|
||||||
derivePublicFromPrivate(key)
|
|
||||||
]).then((keys) => exportKey({
|
|
||||||
privateKey: keys[0],
|
|
||||||
publicKey: keys[1]
|
|
||||||
})).then((keys) => ({
|
|
||||||
privateKey: keys[0],
|
|
||||||
publicKey: keys[1]
|
|
||||||
})), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getRandomValues = function (arr) {
|
|
||||||
return Buffer.from(crypto.getRandomValues(arr))
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.hashAndSign = function (key, msg, callback) {
|
|
||||||
nodeify(crypto.subtle.importKey(
|
|
||||||
'jwk',
|
|
||||||
key,
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['sign']
|
|
||||||
).then((privateKey) => {
|
|
||||||
return crypto.subtle.sign(
|
|
||||||
{name: 'RSASSA-PKCS1-v1_5'},
|
|
||||||
privateKey,
|
|
||||||
Uint8Array.from(msg)
|
|
||||||
)
|
|
||||||
}).then((sig) => Buffer.from(sig)), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.hashAndVerify = function (key, sig, msg, callback) {
|
|
||||||
nodeify(crypto.subtle.importKey(
|
|
||||||
'jwk',
|
|
||||||
key,
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['verify']
|
|
||||||
).then((publicKey) => {
|
|
||||||
return crypto.subtle.verify(
|
|
||||||
{name: 'RSASSA-PKCS1-v1_5'},
|
|
||||||
publicKey,
|
|
||||||
sig,
|
|
||||||
msg
|
|
||||||
)
|
|
||||||
}), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
function exportKey (pair) {
|
|
||||||
return Promise.all([
|
|
||||||
crypto.subtle.exportKey('jwk', pair.privateKey),
|
|
||||||
crypto.subtle.exportKey('jwk', pair.publicKey)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
function derivePublicFromPrivate (jwKey) {
|
|
||||||
return crypto.subtle.importKey(
|
|
||||||
'jwk',
|
|
||||||
{
|
|
||||||
kty: jwKey.kty,
|
|
||||||
n: jwKey.n,
|
|
||||||
e: jwKey.e,
|
|
||||||
alg: jwKey.alg,
|
|
||||||
kid: jwKey.kid
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['verify']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
|
|
||||||
this.seq().obj(
|
|
||||||
this.key('version').int(),
|
|
||||||
this.key('modulus').int(),
|
|
||||||
this.key('publicExponent').int(),
|
|
||||||
this.key('privateExponent').int(),
|
|
||||||
this.key('prime1').int(),
|
|
||||||
this.key('prime2').int(),
|
|
||||||
this.key('exponent1').int(),
|
|
||||||
this.key('exponent2').int(),
|
|
||||||
this.key('coefficient').int()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
|
|
||||||
this.seq().obj(
|
|
||||||
this.key('algorithm').objid({
|
|
||||||
'1.2.840.113549.1.1.1': 'rsa'
|
|
||||||
}),
|
|
||||||
this.key('none').optional().null_(),
|
|
||||||
this.key('curve').optional().objid(),
|
|
||||||
this.key('params').optional().seq().obj(
|
|
||||||
this.key('p').int(),
|
|
||||||
this.key('q').int(),
|
|
||||||
this.key('g').int()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const PublicKey = asn1.define('RSAPublicKey', function () {
|
|
||||||
this.seq().obj(
|
|
||||||
this.key('algorithm').use(AlgorithmIdentifier),
|
|
||||||
this.key('subjectPublicKey').bitstr()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const RSAPublicKey = asn1.define('RSAPublicKey', function () {
|
|
||||||
this.seq().obj(
|
|
||||||
this.key('modulus').int(),
|
|
||||||
this.key('publicExponent').int()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Convert a PKCS#1 in ASN1 DER format to a JWK key
|
|
||||||
exports.pkcs1ToJwk = function (bytes) {
|
|
||||||
const asn1 = RSAPrivateKey.decode(bytes, 'der')
|
|
||||||
|
|
||||||
return {
|
|
||||||
kty: 'RSA',
|
|
||||||
n: toBase64(asn1.modulus),
|
|
||||||
e: toBase64(asn1.publicExponent),
|
|
||||||
d: toBase64(asn1.privateExponent),
|
|
||||||
p: toBase64(asn1.prime1),
|
|
||||||
q: toBase64(asn1.prime2),
|
|
||||||
dp: toBase64(asn1.exponent1),
|
|
||||||
dq: toBase64(asn1.exponent2),
|
|
||||||
qi: toBase64(asn1.coefficient),
|
|
||||||
alg: 'RS256',
|
|
||||||
kid: '2011-04-29'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a JWK key into PKCS#1 in ASN1 DER format
|
|
||||||
exports.jwkToPkcs1 = function (jwk) {
|
|
||||||
return RSAPrivateKey.encode({
|
|
||||||
version: 0,
|
|
||||||
modulus: toBn(jwk.n),
|
|
||||||
publicExponent: toBn(jwk.e),
|
|
||||||
privateExponent: toBn(jwk.d),
|
|
||||||
prime1: toBn(jwk.p),
|
|
||||||
prime2: toBn(jwk.q),
|
|
||||||
exponent1: toBn(jwk.dp),
|
|
||||||
exponent2: toBn(jwk.dq),
|
|
||||||
coefficient: toBn(jwk.qi)
|
|
||||||
}, 'der')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a PKCIX in ASN1 DER format to a JWK key
|
|
||||||
exports.pkixToJwk = function (bytes) {
|
|
||||||
const ndata = PublicKey.decode(bytes, 'der')
|
|
||||||
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
|
|
||||||
|
|
||||||
return {
|
|
||||||
kty: 'RSA',
|
|
||||||
n: toBase64(asn1.modulus),
|
|
||||||
e: toBase64(asn1.publicExponent),
|
|
||||||
alg: 'RS256',
|
|
||||||
kid: '2011-04-29'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a JWK key to PKCIX in ASN1 DER format
|
|
||||||
exports.jwkToPkix = function (jwk) {
|
|
||||||
return PublicKey.encode({
|
|
||||||
algorithm: {
|
|
||||||
algorithm: 'rsa',
|
|
||||||
none: null
|
|
||||||
},
|
|
||||||
subjectPublicKey: {
|
|
||||||
data: RSAPublicKey.encode({
|
|
||||||
modulus: toBn(jwk.n),
|
|
||||||
publicExponent: toBn(jwk.e)
|
|
||||||
}, 'der')
|
|
||||||
}
|
|
||||||
}, 'der')
|
|
||||||
}
|
|
@@ -1,19 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const BN = require('asn1.js').bignum
|
|
||||||
|
|
||||||
// Convert a BN.js instance to a base64 encoded string without padding
|
|
||||||
// Adapted from https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#appendix-C
|
|
||||||
exports.toBase64 = function toBase64 (bn) {
|
|
||||||
let s = bn.toBuffer('be').toString('base64')
|
|
||||||
|
|
||||||
return s
|
|
||||||
.replace(/(=*)$/, '') // Remove any trailing '='s
|
|
||||||
.replace(/\+/g, '-') // 62nd char of encoding
|
|
||||||
.replace(/\//g, '_') // 63rd char of encoding
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a base64 encoded string to a BN.js instance
|
|
||||||
exports.toBn = function toBn (str) {
|
|
||||||
return new BN(Buffer.from(str, 'base64'))
|
|
||||||
}
|
|
@@ -1,14 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
module.exports = function getWebCrypto () {
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
// This is only a shim for interfaces, not for functionality
|
|
||||||
require('webcrypto-shim')(window)
|
|
||||||
|
|
||||||
if (window.crypto) {
|
|
||||||
return window.crypto
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('Please use an environment with crypto support')
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
module.exports = function getWebCrypto () {
|
|
||||||
const WebCrypto = require('node-webcrypto-ossl')
|
|
||||||
const webCrypto = new WebCrypto()
|
|
||||||
return webCrypto
|
|
||||||
}
|
|
37
src/hmac/index-browser.js
Normal file
37
src/hmac/index-browser.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const webcrypto = require('../webcrypto')
|
||||||
|
const lengths = require('./lengths')
|
||||||
|
|
||||||
|
const hashTypes = {
|
||||||
|
SHA1: 'SHA-1',
|
||||||
|
SHA256: 'SHA-256',
|
||||||
|
SHA512: 'SHA-512'
|
||||||
|
}
|
||||||
|
|
||||||
|
const sign = async (key, data) => {
|
||||||
|
const buf = await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data)
|
||||||
|
return new Uint8Array(buf, buf.byteOffset, buf.byteLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.create = async function (hashType, secret) {
|
||||||
|
const hash = hashTypes[hashType]
|
||||||
|
|
||||||
|
const key = await webcrypto.get().subtle.importKey(
|
||||||
|
'raw',
|
||||||
|
secret,
|
||||||
|
{
|
||||||
|
name: 'HMAC',
|
||||||
|
hash: { name: hash }
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['sign']
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
async digest (data) { // eslint-disable-line require-await
|
||||||
|
return sign(key, data)
|
||||||
|
},
|
||||||
|
length: lengths[hashType]
|
||||||
|
}
|
||||||
|
}
|
17
src/hmac/index.js
Normal file
17
src/hmac/index.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const lengths = require('./lengths')
|
||||||
|
|
||||||
|
exports.create = async function (hash, secret) { // eslint-disable-line require-await
|
||||||
|
const res = {
|
||||||
|
async digest (data) { // eslint-disable-line require-await
|
||||||
|
const hmac = crypto.createHmac(hash.toLowerCase(), secret)
|
||||||
|
hmac.update(data)
|
||||||
|
return hmac.digest()
|
||||||
|
},
|
||||||
|
length: lengths[hash]
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
338
src/index.d.ts
vendored
Normal file
338
src/index.d.ts
vendored
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
/**
|
||||||
|
* Supported key types.
|
||||||
|
*/
|
||||||
|
export type KeyType = "Ed25519" | "RSA" | "secp256k1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps an IPFS hash name to its node-forge equivalent.
|
||||||
|
* See https://github.com/multiformats/multihash/blob/master/hashtable.csv
|
||||||
|
*/
|
||||||
|
export type HashType = "SHA1" | "SHA256" | "SHA512";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported curve types.
|
||||||
|
*/
|
||||||
|
export type CurveType = "P-256" | "P-384" | "P-521";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported cipher types.
|
||||||
|
*/
|
||||||
|
export type CipherType = "AES-128" | "AES-256" | "Blowfish";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes an interface to AES encryption (formerly Rijndael),
|
||||||
|
* as defined in U.S. Federal Information Processing Standards Publication 197.
|
||||||
|
* This uses CTR mode.
|
||||||
|
*/
|
||||||
|
export namespace aes {
|
||||||
|
/**
|
||||||
|
* AES Cipher in CTR mode.
|
||||||
|
*/
|
||||||
|
interface Cipher {
|
||||||
|
encrypt(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
decrypt(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new AES Cipher.
|
||||||
|
* @param key The key, if length 16 then AES 128 is used. For length 32, AES 256 is used.
|
||||||
|
* @param iv Must have length 16.
|
||||||
|
*/
|
||||||
|
function create(key: Uint8Array, iv: Uint8Array): Promise<Cipher>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC)
|
||||||
|
* as defined in U.S. Federal Information Processing Standards Publication 198.
|
||||||
|
* An HMAC is a cryptographic hash that uses a key to sign a message.
|
||||||
|
* The receiver verifies the hash by recomputing it using the same key.
|
||||||
|
*/
|
||||||
|
export namespace hmac {
|
||||||
|
/**
|
||||||
|
* HMAC Digest.
|
||||||
|
*/
|
||||||
|
interface Digest {
|
||||||
|
digest(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
length: 20 | 32 | 64 | number;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new HMAC Digest.
|
||||||
|
*/
|
||||||
|
function create(
|
||||||
|
hash: "SHA1" | "SHA256" | "SHA512" | string,
|
||||||
|
secret: Uint8Array
|
||||||
|
): Promise<Digest>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic public key interface.
|
||||||
|
*/
|
||||||
|
export interface PublicKey {
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
equals(key: PublicKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic private key interface.
|
||||||
|
*/
|
||||||
|
export interface PrivateKey {
|
||||||
|
readonly public: PublicKey;
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
sign(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
equals(key: PrivateKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
/**
|
||||||
|
* Gets the ID of the key.
|
||||||
|
*
|
||||||
|
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
|
||||||
|
* The public key is a protobuf encoding containing a type and the DER encoding
|
||||||
|
* of the PKCS SubjectPublicKeyInfo.
|
||||||
|
*/
|
||||||
|
id(): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Exports the password protected key in the format specified.
|
||||||
|
*/
|
||||||
|
export(password: string, format?: "pkcs-8" | string): Promise<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Keystretcher {
|
||||||
|
(res: Uint8Array): Keystretcher;
|
||||||
|
iv: Uint8Array;
|
||||||
|
cipherKey: Uint8Array;
|
||||||
|
macKey: Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StretchPair {
|
||||||
|
k1: Keystretcher;
|
||||||
|
k2: Keystretcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes an interface to various cryptographic key generation routines.
|
||||||
|
* Currently the 'RSA' and 'ed25519' types are supported, although ed25519 keys
|
||||||
|
* support only signing and verification of messages. For encryption / decryption
|
||||||
|
* support, RSA keys should be used.
|
||||||
|
* Installing the libp2p-crypto-secp256k1 module adds support for the 'secp256k1'
|
||||||
|
* type, which supports ECDSA signatures using the secp256k1 elliptic curve
|
||||||
|
* popularized by Bitcoin. This module is not installed by default, and should be
|
||||||
|
* explicitly depended on if your project requires secp256k1 support.
|
||||||
|
*/
|
||||||
|
export namespace keys {
|
||||||
|
export {};
|
||||||
|
export namespace supportedKeys {
|
||||||
|
namespace rsa {
|
||||||
|
class RsaPublicKey implements PublicKey {
|
||||||
|
constructor(key: Uint8Array);
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
encrypt(bytes: Uint8Array): Uint8Array;
|
||||||
|
equals(key: PublicKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RsaPrivateKey implements PrivateKey {
|
||||||
|
constructor(key: any, publicKey: Uint8Array);
|
||||||
|
readonly public: RsaPublicKey;
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
genSecret(): Uint8Array;
|
||||||
|
sign(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
decrypt(bytes: Uint8Array): Uint8Array;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
equals(key: PrivateKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
id(): Promise<string>;
|
||||||
|
export(password: string, format?: string): Promise<string>;
|
||||||
|
}
|
||||||
|
function unmarshalRsaPublicKey(buf: Uint8Array): RsaPublicKey;
|
||||||
|
function unmarshalRsaPrivateKey(buf: Uint8Array): Promise<RsaPrivateKey>;
|
||||||
|
function generateKeyPair(bits: number): Promise<RsaPrivateKey>;
|
||||||
|
function fromJwk(jwk: Uint8Array): Promise<RsaPrivateKey>;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ed25519 {
|
||||||
|
class Ed25519PublicKey implements PublicKey {
|
||||||
|
constructor(key: Uint8Array);
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
encrypt(bytes: Uint8Array): Uint8Array;
|
||||||
|
equals(key: PublicKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ed25519PrivateKey implements PrivateKey {
|
||||||
|
constructor(key: Uint8Array, publicKey: Uint8Array);
|
||||||
|
readonly public: Ed25519PublicKey;
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
sign(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
equals(key: PrivateKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
id(): Promise<string>;
|
||||||
|
export(password: string, format?: string): Promise<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalEd25519PrivateKey(
|
||||||
|
buf: Uint8Array
|
||||||
|
): Promise<Ed25519PrivateKey>;
|
||||||
|
function unmarshalEd25519PublicKey(buf: Uint8Array): Ed25519PublicKey;
|
||||||
|
function generateKeyPair(): Promise<Ed25519PrivateKey>;
|
||||||
|
function generateKeyPairFromSeed(
|
||||||
|
seed: Uint8Array
|
||||||
|
): Promise<Ed25519PrivateKey>;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace secp256k1 {
|
||||||
|
class Secp256k1PublicKey implements PublicKey {
|
||||||
|
constructor(key: Uint8Array);
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
encrypt(bytes: Uint8Array): Uint8Array;
|
||||||
|
equals(key: PublicKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Secp256k1PrivateKey implements PrivateKey {
|
||||||
|
constructor(key: Uint8Array, publicKey: Uint8Array);
|
||||||
|
readonly public: Secp256k1PublicKey;
|
||||||
|
readonly bytes: Uint8Array;
|
||||||
|
sign(data: Uint8Array): Promise<Uint8Array>;
|
||||||
|
marshal(): Uint8Array;
|
||||||
|
equals(key: PrivateKey): boolean;
|
||||||
|
hash(): Promise<Uint8Array>;
|
||||||
|
id(): Promise<string>;
|
||||||
|
export(password: string, format?: string): Promise<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalSecp256k1PrivateKey(
|
||||||
|
bytes: Uint8Array
|
||||||
|
): Promise<Secp256k1PrivateKey>;
|
||||||
|
function unmarshalSecp256k1PublicKey(bytes: Uint8Array): Secp256k1PublicKey;
|
||||||
|
function generateKeyPair(): Promise<Secp256k1PrivateKey>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const keysPBM: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a keypair of the given type and bitsize.
|
||||||
|
* @param type One of the supported key types.
|
||||||
|
* @param bits Number of bits. Minimum of 1024.
|
||||||
|
*/
|
||||||
|
export function generateKeyPair(
|
||||||
|
type: KeyType | string,
|
||||||
|
bits: number
|
||||||
|
): Promise<PrivateKey>;
|
||||||
|
export function generateKeyPair(
|
||||||
|
type: "Ed25519"
|
||||||
|
): Promise<keys.supportedKeys.ed25519.Ed25519PrivateKey>;
|
||||||
|
export function generateKeyPair(
|
||||||
|
type: "RSA",
|
||||||
|
bits: number
|
||||||
|
): Promise<keys.supportedKeys.rsa.RsaPrivateKey>;
|
||||||
|
export function generateKeyPair(
|
||||||
|
type: "secp256k1"
|
||||||
|
): Promise<keys.supportedKeys.secp256k1.Secp256k1PrivateKey>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a keypair of the given type and bitsize.
|
||||||
|
* @param type One of the supported key types. Currently only 'Ed25519' is supported.
|
||||||
|
* @param seed A 32 byte uint8array.
|
||||||
|
* @param bits Number of bits. Minimum of 1024.
|
||||||
|
*/
|
||||||
|
export function generateKeyPairFromSeed(
|
||||||
|
type: KeyType | string,
|
||||||
|
seed: Uint8Array,
|
||||||
|
bits: number
|
||||||
|
): Promise<PrivateKey>;
|
||||||
|
export function generateKeyPairFromSeed(
|
||||||
|
type: "Ed25519",
|
||||||
|
seed: Uint8Array,
|
||||||
|
bits: number
|
||||||
|
): Promise<keys.supportedKeys.ed25519.Ed25519PrivateKey>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an ephemeral public key and returns a function that will compute the shared secret key.
|
||||||
|
* Focuses only on ECDH now, but can be made more general in the future.
|
||||||
|
* @param curve The curve to use. One of 'P-256', 'P-384', 'P-521' is currently supported.
|
||||||
|
*/
|
||||||
|
export function generateEphemeralKeyPair(
|
||||||
|
curve: CurveType | string
|
||||||
|
): Promise<{
|
||||||
|
key: Uint8Array;
|
||||||
|
genSharedKey: (theirPub: Uint8Array, forcePrivate?: any) => Promise<Uint8Array>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a set of keys for each party by stretching the shared key.
|
||||||
|
* @param cipherType The cipher type to use. One of 'AES-128', 'AES-256', or 'Blowfish'
|
||||||
|
* @param hashType The hash type to use. One of 'SHA1', 'SHA2256', or 'SHA2512'.
|
||||||
|
* @param secret The shared key secret.
|
||||||
|
*/
|
||||||
|
export function keyStretcher(
|
||||||
|
cipherType: CipherType | string,
|
||||||
|
hashType: HashType | string,
|
||||||
|
secret: Uint8Array | string
|
||||||
|
): Promise<StretchPair>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a protobuf serialized public key into its representative object.
|
||||||
|
* @param buf The protobuf serialized public key.
|
||||||
|
*/
|
||||||
|
export function unmarshalPublicKey(buf: Uint8Array): PublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a public key object into a protobuf serialized public key.
|
||||||
|
* @param key An RSA, Ed25519, or Secp256k1 public key object.
|
||||||
|
* @param type One of the supported key types.
|
||||||
|
*/
|
||||||
|
export function marshalPublicKey(key: PublicKey, type?: KeyType | string): Uint8Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a protobuf serialized private key into its representative object.
|
||||||
|
* @param buf The protobuf serialized private key.
|
||||||
|
*/
|
||||||
|
export function unmarshalPrivateKey(buf: Uint8Array): Promise<PrivateKey>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a private key object into a protobuf serialized private key.
|
||||||
|
* @param key An RSA, Ed25519, or Secp256k1 private key object.
|
||||||
|
* @param type One of the supported key types.
|
||||||
|
*/
|
||||||
|
export function marshalPrivateKey(key: PrivateKey, type?: KeyType | string): Uint8Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a PEM password protected private key into its representative object.
|
||||||
|
* @param pem Password protected private key in PEM format.
|
||||||
|
* @param password The password used to protect the key.
|
||||||
|
*/
|
||||||
|
function _import(pem: string, password: string, format?: string): Promise<supportedKeys.rsa.RsaPrivateKey>;
|
||||||
|
export { _import as import };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a Uint8Array populated by random bytes.
|
||||||
|
* @param The size of the random bytes Uint8Array.
|
||||||
|
*/
|
||||||
|
export function randomBytes(number: number): Uint8Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the Password-Based Key Derivation Function 2.
|
||||||
|
* @param password The password.
|
||||||
|
* @param salt The salt.
|
||||||
|
* @param iterations Number of iterations to use.
|
||||||
|
* @param keySize The size of the output key in bytes.
|
||||||
|
* @param hash The hash name ('sha1', 'sha2-512, ...)
|
||||||
|
*/
|
||||||
|
export function pbkdf2(
|
||||||
|
password: string | Uint8Array,
|
||||||
|
salt: string | Uint8Array,
|
||||||
|
iterations: number,
|
||||||
|
keySize: number,
|
||||||
|
hash: string
|
||||||
|
): Uint8Array;
|
78
src/index.js
78
src/index.js
@@ -1,73 +1,11 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const protobuf = require('protocol-buffers')
|
const hmac = require('./hmac')
|
||||||
const pbm = protobuf(require('./crypto.proto'))
|
const aes = require('./aes')
|
||||||
const c = require('./crypto')
|
const keys = require('./keys')
|
||||||
|
|
||||||
exports.hmac = c.hmac
|
exports.aes = aes
|
||||||
exports.aes = c.aes
|
exports.hmac = hmac
|
||||||
exports.webcrypto = c.webcrypto
|
exports.keys = keys
|
||||||
|
exports.randomBytes = require('./random-bytes')
|
||||||
const keys = exports.keys = require('./keys')
|
exports.pbkdf2 = require('./pbkdf2')
|
||||||
exports.keyStretcher = require('./key-stretcher')
|
|
||||||
exports.generateEphemeralKeyPair = require('./ephemeral-keys')
|
|
||||||
|
|
||||||
// Generates a keypair of the given type and bitsize
|
|
||||||
exports.generateKeyPair = (type, bits, cb) => {
|
|
||||||
let key = keys[type.toLowerCase()]
|
|
||||||
if (!key) {
|
|
||||||
return cb(new Error('invalid or unsupported key type'))
|
|
||||||
}
|
|
||||||
|
|
||||||
key.generateKeyPair(bits, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts a protobuf serialized public key into its
|
|
||||||
// representative object
|
|
||||||
exports.unmarshalPublicKey = (buf) => {
|
|
||||||
const decoded = pbm.PublicKey.decode(buf)
|
|
||||||
|
|
||||||
switch (decoded.Type) {
|
|
||||||
case pbm.KeyType.RSA:
|
|
||||||
return keys.rsa.unmarshalRsaPublicKey(decoded.Data)
|
|
||||||
default:
|
|
||||||
throw new Error('invalid or unsupported key type')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts a public key object into a protobuf serialized public key
|
|
||||||
exports.marshalPublicKey = (key, type) => {
|
|
||||||
type = (type || 'rsa').toLowerCase()
|
|
||||||
|
|
||||||
// for now only rsa is supported
|
|
||||||
if (type !== 'rsa') {
|
|
||||||
throw new Error('invalid or unsupported key type')
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts a protobuf serialized private key into its
|
|
||||||
// representative object
|
|
||||||
exports.unmarshalPrivateKey = (buf, callback) => {
|
|
||||||
const decoded = pbm.PrivateKey.decode(buf)
|
|
||||||
|
|
||||||
switch (decoded.Type) {
|
|
||||||
case pbm.KeyType.RSA:
|
|
||||||
return keys.rsa.unmarshalRsaPrivateKey(decoded.Data, callback)
|
|
||||||
default:
|
|
||||||
callback(new Error('invalid or unsupported key type'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts a private key object into a protobuf serialized private key
|
|
||||||
exports.marshalPrivateKey = (key, type) => {
|
|
||||||
type = (type || 'rsa').toLowerCase()
|
|
||||||
|
|
||||||
// for now only rsa is supported
|
|
||||||
if (type !== 'rsa') {
|
|
||||||
throw new Error('invalid or unsupported key type')
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.bytes
|
|
||||||
}
|
|
||||||
|
@@ -1,108 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const crypto = require('./crypto')
|
|
||||||
const whilst = require('async/whilst')
|
|
||||||
|
|
||||||
const cipherMap = {
|
|
||||||
'AES-128': {
|
|
||||||
ivSize: 16,
|
|
||||||
keySize: 16
|
|
||||||
},
|
|
||||||
'AES-256': {
|
|
||||||
ivSize: 16,
|
|
||||||
keySize: 32
|
|
||||||
},
|
|
||||||
Blowfish: {
|
|
||||||
ivSize: 8,
|
|
||||||
cipherKeySize: 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a set of keys for each party by stretching the shared key.
|
|
||||||
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
|
|
||||||
module.exports = (cipherType, hash, secret, callback) => {
|
|
||||||
const cipher = cipherMap[cipherType]
|
|
||||||
|
|
||||||
if (!cipher) {
|
|
||||||
return callback(new Error('unkown cipherType passed'))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hash) {
|
|
||||||
return callback(new Error('unkown hashType passed'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const cipherKeySize = cipher.keySize
|
|
||||||
const ivSize = cipher.ivSize
|
|
||||||
const hmacKeySize = 20
|
|
||||||
const seed = Buffer.from('key expansion')
|
|
||||||
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
|
|
||||||
|
|
||||||
crypto.hmac.create(hash, secret, (err, m) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
m.digest(seed, (err, a) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = []
|
|
||||||
let j = 0
|
|
||||||
|
|
||||||
whilst(
|
|
||||||
() => j < resultLength,
|
|
||||||
stretch,
|
|
||||||
finish
|
|
||||||
)
|
|
||||||
|
|
||||||
function stretch (cb) {
|
|
||||||
m.digest(Buffer.concat([a, seed]), (err, b) => {
|
|
||||||
if (err) {
|
|
||||||
return cb(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
let todo = b.length
|
|
||||||
|
|
||||||
if (j + todo > resultLength) {
|
|
||||||
todo = resultLength - j
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push(b)
|
|
||||||
|
|
||||||
j += todo
|
|
||||||
|
|
||||||
m.digest(a, (err, _a) => {
|
|
||||||
if (err) {
|
|
||||||
return cb(err)
|
|
||||||
}
|
|
||||||
a = _a
|
|
||||||
cb()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function finish (err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const half = resultLength / 2
|
|
||||||
const resultBuffer = Buffer.concat(result)
|
|
||||||
const r1 = resultBuffer.slice(0, half)
|
|
||||||
const r2 = resultBuffer.slice(half, resultLength)
|
|
||||||
|
|
||||||
const createKey = (res) => ({
|
|
||||||
iv: res.slice(0, ivSize),
|
|
||||||
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
|
|
||||||
macKey: res.slice(ivSize + cipherKeySize)
|
|
||||||
})
|
|
||||||
|
|
||||||
callback(null, {
|
|
||||||
k1: createKey(r1),
|
|
||||||
k2: createKey(r2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
121
src/keys/ecdh-browser.js
Normal file
121
src/keys/ecdh-browser.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const webcrypto = require('../webcrypto')
|
||||||
|
const { base64urlToBuffer } = require('../util')
|
||||||
|
const validateCurveType = require('./validate-curve-type')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
const uint8ArrayConcat = require('uint8arrays/concat')
|
||||||
|
const uint8ArrayEquals = require('uint8arrays/equals')
|
||||||
|
|
||||||
|
const bits = {
|
||||||
|
'P-256': 256,
|
||||||
|
'P-384': 384,
|
||||||
|
'P-521': 521
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.generateEphmeralKeyPair = async function (curve) {
|
||||||
|
validateCurveType(Object.keys(bits), curve)
|
||||||
|
const pair = await webcrypto.get().subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: 'ECDH',
|
||||||
|
namedCurve: curve
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['deriveBits']
|
||||||
|
)
|
||||||
|
|
||||||
|
// forcePrivate is used for testing only
|
||||||
|
const genSharedKey = async (theirPub, forcePrivate) => {
|
||||||
|
let privateKey
|
||||||
|
|
||||||
|
if (forcePrivate) {
|
||||||
|
privateKey = await webcrypto.get().subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
unmarshalPrivateKey(curve, forcePrivate),
|
||||||
|
{
|
||||||
|
name: 'ECDH',
|
||||||
|
namedCurve: curve
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['deriveBits']
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
privateKey = pair.privateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = [
|
||||||
|
await webcrypto.get().subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
unmarshalPublicKey(curve, theirPub),
|
||||||
|
{
|
||||||
|
name: 'ECDH',
|
||||||
|
namedCurve: curve
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
privateKey
|
||||||
|
]
|
||||||
|
|
||||||
|
const buffer = await webcrypto.get().subtle.deriveBits(
|
||||||
|
{
|
||||||
|
name: 'ECDH',
|
||||||
|
namedCurve: curve,
|
||||||
|
public: keys[0]
|
||||||
|
},
|
||||||
|
keys[1],
|
||||||
|
bits[curve]
|
||||||
|
)
|
||||||
|
|
||||||
|
return new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicKey = await webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: marshalPublicKey(publicKey),
|
||||||
|
genSharedKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const curveLengths = {
|
||||||
|
'P-256': 32,
|
||||||
|
'P-384': 48,
|
||||||
|
'P-521': 66
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal converts a jwk encodec ECDH public key into the
|
||||||
|
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
|
||||||
|
// go-ipfs uses)
|
||||||
|
function marshalPublicKey (jwk) {
|
||||||
|
const byteLen = curveLengths[jwk.crv]
|
||||||
|
|
||||||
|
return uint8ArrayConcat([
|
||||||
|
Uint8Array.from([4]), // uncompressed point
|
||||||
|
base64urlToBuffer(jwk.x, byteLen),
|
||||||
|
base64urlToBuffer(jwk.y, byteLen)
|
||||||
|
], 1 + byteLen * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
|
||||||
|
function unmarshalPublicKey (curve, key) {
|
||||||
|
const byteLen = curveLengths[curve]
|
||||||
|
|
||||||
|
if (uint8ArrayEquals(!key.slice(0, 1), Uint8Array.from([4]))) {
|
||||||
|
throw errcode(new Error('Cannot unmarshal public key - invalid key format'), 'ERR_INVALID_KEY_FORMAT')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
kty: 'EC',
|
||||||
|
crv: curve,
|
||||||
|
x: uint8ArrayToString(key.slice(1, byteLen + 1), 'base64url'),
|
||||||
|
y: uint8ArrayToString(key.slice(1 + byteLen), 'base64url'),
|
||||||
|
ext: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unmarshalPrivateKey = (curve, key) => ({
|
||||||
|
...unmarshalPublicKey(curve, key.public),
|
||||||
|
d: uint8ArrayToString(key.private, 'base64url')
|
||||||
|
})
|
28
src/keys/ecdh.js
Normal file
28
src/keys/ecdh.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const validateCurveType = require('./validate-curve-type')
|
||||||
|
|
||||||
|
const curves = {
|
||||||
|
'P-256': 'prime256v1',
|
||||||
|
'P-384': 'secp384r1',
|
||||||
|
'P-521': 'secp521r1'
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.generateEphmeralKeyPair = async function (curve) { // eslint-disable-line require-await
|
||||||
|
validateCurveType(Object.keys(curves), curve)
|
||||||
|
|
||||||
|
const ecdh = crypto.createECDH(curves[curve])
|
||||||
|
ecdh.generateKeys()
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: ecdh.getPublicKey(),
|
||||||
|
async genSharedKey (theirPub, forcePrivate) { // eslint-disable-line require-await
|
||||||
|
if (forcePrivate) {
|
||||||
|
ecdh.setPrivateKey(forcePrivate.private)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ecdh.computeSecret(theirPub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
152
src/keys/ed25519-class.js
Normal file
152
src/keys/ed25519-class.js
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const sha = require('multihashing-async/src/sha')
|
||||||
|
const protobuf = require('protons')
|
||||||
|
const multibase = require('multibase')
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const uint8ArrayEquals = require('uint8arrays/equals')
|
||||||
|
|
||||||
|
const crypto = require('./ed25519')
|
||||||
|
const pbm = protobuf(require('./keys.proto'))
|
||||||
|
const exporter = require('./exporter')
|
||||||
|
|
||||||
|
class Ed25519PublicKey {
|
||||||
|
constructor (key) {
|
||||||
|
this._key = ensureKey(key, crypto.publicKeyLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify (data, sig) { // eslint-disable-line require-await
|
||||||
|
return crypto.hashAndVerify(this._key, sig, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal () {
|
||||||
|
return this._key
|
||||||
|
}
|
||||||
|
|
||||||
|
get bytes () {
|
||||||
|
return pbm.PublicKey.encode({
|
||||||
|
Type: pbm.KeyType.Ed25519,
|
||||||
|
Data: this.marshal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
equals (key) {
|
||||||
|
return uint8ArrayEquals(this.bytes, key.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
async hash () { // eslint-disable-line require-await
|
||||||
|
return sha.multihashing(this.bytes, 'sha2-256')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ed25519PrivateKey {
|
||||||
|
// key - 64 byte Uint8Array containing private key
|
||||||
|
// publicKey - 32 byte Uint8Array containing public key
|
||||||
|
constructor (key, publicKey) {
|
||||||
|
this._key = ensureKey(key, crypto.privateKeyLength)
|
||||||
|
this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
async sign (message) { // eslint-disable-line require-await
|
||||||
|
return crypto.hashAndSign(this._key, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
get public () {
|
||||||
|
return new Ed25519PublicKey(this._publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal () {
|
||||||
|
return this._key
|
||||||
|
}
|
||||||
|
|
||||||
|
get bytes () {
|
||||||
|
return pbm.PrivateKey.encode({
|
||||||
|
Type: pbm.KeyType.Ed25519,
|
||||||
|
Data: this.marshal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
equals (key) {
|
||||||
|
return uint8ArrayEquals(this.bytes, key.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
async hash () { // eslint-disable-line require-await
|
||||||
|
return sha.multihashing(this.bytes, 'sha2-256')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID of the key.
|
||||||
|
*
|
||||||
|
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
|
||||||
|
* The public key is a protobuf encoding containing a type and the DER encoding
|
||||||
|
* of the PKCS SubjectPublicKeyInfo.
|
||||||
|
*
|
||||||
|
* @returns {Promise<String>}
|
||||||
|
*/
|
||||||
|
async id () {
|
||||||
|
const hash = await this.public.hash()
|
||||||
|
return multibase.encode('base58btc', hash).toString().slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the key into a password protected `format`
|
||||||
|
*
|
||||||
|
* @param {string} password - The password to encrypt the key
|
||||||
|
* @param {string} [format=libp2p-key] - The format in which to export as
|
||||||
|
* @returns {Promise<Uint8Array>} The encrypted private key
|
||||||
|
*/
|
||||||
|
async export (password, format = 'libp2p-key') { // eslint-disable-line require-await
|
||||||
|
if (format === 'libp2p-key') {
|
||||||
|
return exporter.export(this.bytes, password)
|
||||||
|
} else {
|
||||||
|
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalEd25519PrivateKey (bytes) {
|
||||||
|
// Try the old, redundant public key version
|
||||||
|
if (bytes.length > crypto.privateKeyLength) {
|
||||||
|
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
|
||||||
|
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
|
||||||
|
const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
|
||||||
|
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = ensureKey(bytes, crypto.privateKeyLength)
|
||||||
|
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
|
||||||
|
const publicKeyBytes = bytes.slice(crypto.publicKeyLength)
|
||||||
|
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalEd25519PublicKey (bytes) {
|
||||||
|
bytes = ensureKey(bytes, crypto.publicKeyLength)
|
||||||
|
return new Ed25519PublicKey(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateKeyPair () {
|
||||||
|
const { privateKey, publicKey } = await crypto.generateKey()
|
||||||
|
return new Ed25519PrivateKey(privateKey, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateKeyPairFromSeed (seed) {
|
||||||
|
const { privateKey, publicKey } = await crypto.generateKeyFromSeed(seed)
|
||||||
|
return new Ed25519PrivateKey(privateKey, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureKey (key, length) {
|
||||||
|
key = Uint8Array.from(key || [])
|
||||||
|
if (key.length !== length) {
|
||||||
|
throw errcode(new Error(`Key must be a Uint8Array of length ${length}, got ${key.length}`), 'ERR_INVALID_KEY_TYPE')
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Ed25519PublicKey,
|
||||||
|
Ed25519PrivateKey,
|
||||||
|
unmarshalEd25519PrivateKey,
|
||||||
|
unmarshalEd25519PublicKey,
|
||||||
|
generateKeyPair,
|
||||||
|
generateKeyPairFromSeed
|
||||||
|
}
|
24
src/keys/ed25519.js
Normal file
24
src/keys/ed25519.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
require('node-forge/lib/ed25519')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
exports.publicKeyLength = forge.pki.ed25519.constants.PUBLIC_KEY_BYTE_LENGTH
|
||||||
|
exports.privateKeyLength = forge.pki.ed25519.constants.PRIVATE_KEY_BYTE_LENGTH
|
||||||
|
|
||||||
|
exports.generateKey = async function () { // eslint-disable-line require-await
|
||||||
|
return forge.pki.ed25519.generateKeyPair()
|
||||||
|
}
|
||||||
|
|
||||||
|
// seed should be a 32 byte uint8array
|
||||||
|
exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line require-await
|
||||||
|
return forge.pki.ed25519.generateKeyPair({ seed })
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
|
||||||
|
return forge.pki.ed25519.sign({ message: msg, privateKey: key })
|
||||||
|
// return Uint8Array.from(nacl.sign.detached(msg, key))
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await
|
||||||
|
return forge.pki.ed25519.verify({ signature: sig, message: msg, publicKey: key })
|
||||||
|
}
|
@@ -1,11 +1,9 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const crypto = require('./crypto')
|
const ecdh = require('./ecdh')
|
||||||
|
|
||||||
// Generates an ephemeral public key and returns a function that will compute
|
// Generates an ephemeral public key and returns a function that will compute
|
||||||
// the shared secret key.
|
// the shared secret key.
|
||||||
//
|
//
|
||||||
// Focuses only on ECDH now, but can be made more general in the future.
|
// Focuses only on ECDH now, but can be made more general in the future.
|
||||||
module.exports = (curve, callback) => {
|
module.exports = async (curve) => ecdh.generateEphmeralKeyPair(curve) // eslint-disable-line require-await
|
||||||
crypto.ecdh.generateEphmeralKeyPair(curve, callback)
|
|
||||||
}
|
|
22
src/keys/exporter.js
Normal file
22
src/keys/exporter.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const multibase = require('multibase')
|
||||||
|
const ciphers = require('../ciphers/aes-gcm')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Exports the given PrivateKey as a base64 encoded string.
|
||||||
|
* The PrivateKey is encrypted via a password derived PBKDF2 key
|
||||||
|
* leveraging the aes-gcm cipher algorithm.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array} privateKey The PrivateKey protobuf
|
||||||
|
* @param {string} password
|
||||||
|
* @returns {Promise<string>} A base64 encoded string
|
||||||
|
*/
|
||||||
|
export: async function (privateKey, password) {
|
||||||
|
const cipher = ciphers.create()
|
||||||
|
const encryptedKey = await cipher.encrypt(privateKey, password)
|
||||||
|
const base64 = multibase.names.base64
|
||||||
|
return base64.encode(encryptedKey)
|
||||||
|
}
|
||||||
|
}
|
22
src/keys/importer.js
Normal file
22
src/keys/importer.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const multibase = require('multibase')
|
||||||
|
const ciphers = require('../ciphers/aes-gcm')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Attempts to decrypt a base64 encoded PrivateKey string
|
||||||
|
* with the given password. The privateKey must have been exported
|
||||||
|
* using the same password and underlying cipher (aes-gcm)
|
||||||
|
*
|
||||||
|
* @param {string} privateKey A base64 encoded encrypted key
|
||||||
|
* @param {string} password
|
||||||
|
* @returns {Promise<Uint8Array>} The private key protobuf
|
||||||
|
*/
|
||||||
|
import: async function (privateKey, password) {
|
||||||
|
const base64 = multibase.names.base64
|
||||||
|
const encryptedKey = base64.decode(privateKey)
|
||||||
|
const cipher = ciphers.create()
|
||||||
|
return await cipher.decrypt(encryptedKey, password)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,135 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
module.exports = {
|
const protobuf = require('protons')
|
||||||
rsa: require('./rsa')
|
const keysPBM = protobuf(require('./keys.proto'))
|
||||||
|
require('node-forge/lib/asn1')
|
||||||
|
require('node-forge/lib/pbe')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
const importer = require('./importer')
|
||||||
|
|
||||||
|
exports = module.exports
|
||||||
|
|
||||||
|
const supportedKeys = {
|
||||||
|
rsa: require('./rsa-class'),
|
||||||
|
ed25519: require('./ed25519-class'),
|
||||||
|
secp256k1: require('./secp256k1-class')(keysPBM, require('../random-bytes'))
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.supportedKeys = supportedKeys
|
||||||
|
exports.keysPBM = keysPBM
|
||||||
|
|
||||||
|
const ErrMissingSecp256K1 = {
|
||||||
|
message: 'secp256k1 support requires libp2p-crypto-secp256k1 package',
|
||||||
|
code: 'ERR_MISSING_PACKAGE'
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeToKey (type) {
|
||||||
|
const key = supportedKeys[type.toLowerCase()]
|
||||||
|
if (!key) {
|
||||||
|
const supported = Object.keys(supportedKeys).join(' / ')
|
||||||
|
throw errcode(new Error(`invalid or unsupported key type ${type}. Must be ${supported}`), 'ERR_UNSUPPORTED_KEY_TYPE')
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.keyStretcher = require('./key-stretcher')
|
||||||
|
exports.generateEphemeralKeyPair = require('./ephemeral-keys')
|
||||||
|
|
||||||
|
// Generates a keypair of the given type and bitsize
|
||||||
|
exports.generateKeyPair = async (type, bits) => { // eslint-disable-line require-await
|
||||||
|
return typeToKey(type).generateKeyPair(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a keypair of the given type and bitsize
|
||||||
|
// seed is a 32 byte uint8array
|
||||||
|
exports.generateKeyPairFromSeed = async (type, seed, bits) => { // eslint-disable-line require-await
|
||||||
|
const key = typeToKey(type)
|
||||||
|
if (type.toLowerCase() !== 'ed25519') {
|
||||||
|
throw errcode(new Error('Seed key derivation is unimplemented for RSA or secp256k1'), 'ERR_UNSUPPORTED_KEY_DERIVATION_TYPE')
|
||||||
|
}
|
||||||
|
return key.generateKeyPairFromSeed(seed, bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a protobuf serialized public key into its
|
||||||
|
// representative object
|
||||||
|
exports.unmarshalPublicKey = (buf) => {
|
||||||
|
const decoded = keysPBM.PublicKey.decode(buf)
|
||||||
|
const data = decoded.Data
|
||||||
|
|
||||||
|
switch (decoded.Type) {
|
||||||
|
case keysPBM.KeyType.RSA:
|
||||||
|
return supportedKeys.rsa.unmarshalRsaPublicKey(data)
|
||||||
|
case keysPBM.KeyType.Ed25519:
|
||||||
|
return supportedKeys.ed25519.unmarshalEd25519PublicKey(data)
|
||||||
|
case keysPBM.KeyType.Secp256k1:
|
||||||
|
if (supportedKeys.secp256k1) {
|
||||||
|
return supportedKeys.secp256k1.unmarshalSecp256k1PublicKey(data)
|
||||||
|
} else {
|
||||||
|
throw errcode(new Error(ErrMissingSecp256K1.message), ErrMissingSecp256K1.code)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
typeToKey(decoded.Type) // throws because type is not supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a public key object into a protobuf serialized public key
|
||||||
|
exports.marshalPublicKey = (key, type) => {
|
||||||
|
type = (type || 'rsa').toLowerCase()
|
||||||
|
typeToKey(type) // check type
|
||||||
|
return key.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a protobuf serialized private key into its
|
||||||
|
// representative object
|
||||||
|
exports.unmarshalPrivateKey = async (buf) => { // eslint-disable-line require-await
|
||||||
|
const decoded = keysPBM.PrivateKey.decode(buf)
|
||||||
|
const data = decoded.Data
|
||||||
|
|
||||||
|
switch (decoded.Type) {
|
||||||
|
case keysPBM.KeyType.RSA:
|
||||||
|
return supportedKeys.rsa.unmarshalRsaPrivateKey(data)
|
||||||
|
case keysPBM.KeyType.Ed25519:
|
||||||
|
return supportedKeys.ed25519.unmarshalEd25519PrivateKey(data)
|
||||||
|
case keysPBM.KeyType.Secp256k1:
|
||||||
|
if (supportedKeys.secp256k1) {
|
||||||
|
return supportedKeys.secp256k1.unmarshalSecp256k1PrivateKey(data)
|
||||||
|
} else {
|
||||||
|
throw errcode(new Error(ErrMissingSecp256K1.message), ErrMissingSecp256K1.code)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
typeToKey(decoded.Type) // throws because type is not supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a private key object into a protobuf serialized private key
|
||||||
|
exports.marshalPrivateKey = (key, type) => {
|
||||||
|
type = (type || 'rsa').toLowerCase()
|
||||||
|
typeToKey(type) // check type
|
||||||
|
return key.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} encryptedKey
|
||||||
|
* @param {string} password
|
||||||
|
*/
|
||||||
|
exports.import = async (encryptedKey, password) => { // eslint-disable-line require-await
|
||||||
|
try {
|
||||||
|
const key = await importer.import(encryptedKey, password)
|
||||||
|
return exports.unmarshalPrivateKey(key)
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore and try the old pem decrypt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only rsa supports pem right now
|
||||||
|
const key = forge.pki.decryptRsaPrivateKey(encryptedKey, password)
|
||||||
|
if (key === null) {
|
||||||
|
throw errcode(new Error('Cannot read the key, most likely the password is wrong or not a RSA key'), 'ERR_CANNOT_DECRYPT_PEM')
|
||||||
|
}
|
||||||
|
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
|
||||||
|
der = uint8ArrayFromString(der.getBytes(), 'ascii')
|
||||||
|
return supportedKeys.rsa.unmarshalRsaPrivateKey(der)
|
||||||
}
|
}
|
||||||
|
22
src/keys/jwk2pem.js
Normal file
22
src/keys/jwk2pem.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
require('node-forge/lib/rsa')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
const { base64urlToBigInteger } = require('../util')
|
||||||
|
|
||||||
|
function convert (key, types) {
|
||||||
|
return types.map(t => base64urlToBigInteger(key[t]))
|
||||||
|
}
|
||||||
|
|
||||||
|
function jwk2priv (key) {
|
||||||
|
return forge.pki.setRsaPrivateKey(...convert(key, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']))
|
||||||
|
}
|
||||||
|
|
||||||
|
function jwk2pub (key) {
|
||||||
|
return forge.pki.setRsaPublicKey(...convert(key, ['n', 'e']))
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
jwk2pub,
|
||||||
|
jwk2priv
|
||||||
|
}
|
77
src/keys/key-stretcher.js
Normal file
77
src/keys/key-stretcher.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const uint8ArrayConcat = require('uint8arrays/concat')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
const hmac = require('../hmac')
|
||||||
|
|
||||||
|
const cipherMap = {
|
||||||
|
'AES-128': {
|
||||||
|
ivSize: 16,
|
||||||
|
keySize: 16
|
||||||
|
},
|
||||||
|
'AES-256': {
|
||||||
|
ivSize: 16,
|
||||||
|
keySize: 32
|
||||||
|
},
|
||||||
|
Blowfish: {
|
||||||
|
ivSize: 8,
|
||||||
|
cipherKeySize: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a set of keys for each party by stretching the shared key.
|
||||||
|
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
|
||||||
|
module.exports = async (cipherType, hash, secret) => {
|
||||||
|
const cipher = cipherMap[cipherType]
|
||||||
|
|
||||||
|
if (!cipher) {
|
||||||
|
const allowed = Object.keys(cipherMap).join(' / ')
|
||||||
|
throw errcode(new Error(`unknown cipher type '${cipherType}'. Must be ${allowed}`), 'ERR_INVALID_CIPHER_TYPE')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash) {
|
||||||
|
throw errcode(new Error('missing hash type'), 'ERR_MISSING_HASH_TYPE')
|
||||||
|
}
|
||||||
|
|
||||||
|
const cipherKeySize = cipher.keySize
|
||||||
|
const ivSize = cipher.ivSize
|
||||||
|
const hmacKeySize = 20
|
||||||
|
const seed = uint8ArrayFromString('key expansion')
|
||||||
|
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
|
||||||
|
|
||||||
|
const m = await hmac.create(hash, secret)
|
||||||
|
let a = await m.digest(seed)
|
||||||
|
|
||||||
|
const result = []
|
||||||
|
let j = 0
|
||||||
|
|
||||||
|
while (j < resultLength) {
|
||||||
|
const b = await m.digest(uint8ArrayConcat([a, seed]))
|
||||||
|
let todo = b.length
|
||||||
|
|
||||||
|
if (j + todo > resultLength) {
|
||||||
|
todo = resultLength - j
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(b)
|
||||||
|
j += todo
|
||||||
|
a = await m.digest(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
const half = resultLength / 2
|
||||||
|
const resultBuffer = uint8ArrayConcat(result)
|
||||||
|
const r1 = resultBuffer.slice(0, half)
|
||||||
|
const r2 = resultBuffer.slice(half, resultLength)
|
||||||
|
|
||||||
|
const createKey = (res) => ({
|
||||||
|
iv: res.slice(0, ivSize),
|
||||||
|
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
|
||||||
|
macKey: res.slice(ivSize + cipherKeySize)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
k1: createKey(r1),
|
||||||
|
k2: createKey(r2)
|
||||||
|
}
|
||||||
|
}
|
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
module.exports = `enum KeyType {
|
module.exports = `enum KeyType {
|
||||||
RSA = 0;
|
RSA = 0;
|
||||||
|
Ed25519 = 1;
|
||||||
|
Secp256k1 = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PublicKey {
|
message PublicKey {
|
||||||
required KeyType Type = 1;
|
required KeyType Type = 1;
|
||||||
required bytes Data = 2;
|
required bytes Data = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PrivateKey {
|
message PrivateKey {
|
||||||
required KeyType Type = 1;
|
required KeyType Type = 1;
|
||||||
required bytes Data = 2;
|
required bytes Data = 2;
|
153
src/keys/rsa-browser.js
Normal file
153
src/keys/rsa-browser.js
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const webcrypto = require('../webcrypto')
|
||||||
|
const randomBytes = require('../random-bytes')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
exports.utils = require('./rsa-utils')
|
||||||
|
|
||||||
|
exports.generateKey = async function (bits) {
|
||||||
|
const pair = await webcrypto.get().subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
modulusLength: bits,
|
||||||
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||||
|
hash: { name: 'SHA-256' }
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign', 'verify']
|
||||||
|
)
|
||||||
|
|
||||||
|
const keys = await exportKey(pair)
|
||||||
|
|
||||||
|
return {
|
||||||
|
privateKey: keys[0],
|
||||||
|
publicKey: keys[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes a jwk key
|
||||||
|
exports.unmarshalPrivateKey = async function (key) {
|
||||||
|
const privateKey = await webcrypto.get().subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: { name: 'SHA-256' }
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign']
|
||||||
|
)
|
||||||
|
|
||||||
|
const pair = [
|
||||||
|
privateKey,
|
||||||
|
await derivePublicFromPrivate(key)
|
||||||
|
]
|
||||||
|
|
||||||
|
const keys = await exportKey({
|
||||||
|
privateKey: pair[0],
|
||||||
|
publicKey: pair[1]
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
privateKey: keys[0],
|
||||||
|
publicKey: keys[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getRandomValues = randomBytes
|
||||||
|
|
||||||
|
exports.hashAndSign = async function (key, msg) {
|
||||||
|
const privateKey = await webcrypto.get().subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: { name: 'SHA-256' }
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['sign']
|
||||||
|
)
|
||||||
|
|
||||||
|
const sig = await webcrypto.get().subtle.sign(
|
||||||
|
{ name: 'RSASSA-PKCS1-v1_5' },
|
||||||
|
privateKey,
|
||||||
|
Uint8Array.from(msg)
|
||||||
|
)
|
||||||
|
|
||||||
|
return new Uint8Array(sig, sig.byteOffset, sig.byteLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.hashAndVerify = async function (key, sig, msg) {
|
||||||
|
const publicKey = await webcrypto.get().subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: { name: 'SHA-256' }
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['verify']
|
||||||
|
)
|
||||||
|
|
||||||
|
return webcrypto.get().subtle.verify(
|
||||||
|
{ name: 'RSASSA-PKCS1-v1_5' },
|
||||||
|
publicKey,
|
||||||
|
sig,
|
||||||
|
msg
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportKey (pair) {
|
||||||
|
return Promise.all([
|
||||||
|
webcrypto.get().subtle.exportKey('jwk', pair.privateKey),
|
||||||
|
webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function derivePublicFromPrivate (jwKey) {
|
||||||
|
return webcrypto.get().subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
{
|
||||||
|
kty: jwKey.kty,
|
||||||
|
n: jwKey.n,
|
||||||
|
e: jwKey.e
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: { name: 'SHA-256' }
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['verify']
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
RSA encryption/decryption for the browser with webcrypto workarround
|
||||||
|
"bloody dark magic. webcrypto's why."
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
- Convert JWK to nodeForge
|
||||||
|
- Convert msg Uint8Array to nodeForge buffer: ByteBuffer is a "binary-string backed buffer", so let's make our Uint8Array a binary string
|
||||||
|
- Convert resulting nodeForge buffer to Uint8Array: it returns a binary string, turn that into a Uint8Array
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { jwk2pub, jwk2priv } = require('./jwk2pem')
|
||||||
|
|
||||||
|
function convertKey (key, pub, msg, handle) {
|
||||||
|
const fkey = pub ? jwk2pub(key) : jwk2priv(key)
|
||||||
|
const fmsg = uint8ArrayToString(Uint8Array.from(msg), 'ascii')
|
||||||
|
const fomsg = handle(fmsg, fkey)
|
||||||
|
return uint8ArrayFromString(fomsg, 'ascii')
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.encrypt = function (key, msg) {
|
||||||
|
return convertKey(key, true, msg, (msg, key) => key.encrypt(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.decrypt = function (key, msg) {
|
||||||
|
return convertKey(key, false, msg, (msg, key) => key.decrypt(msg))
|
||||||
|
}
|
166
src/keys/rsa-class.js
Normal file
166
src/keys/rsa-class.js
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const sha = require('multihashing-async/src/sha')
|
||||||
|
const protobuf = require('protons')
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const uint8ArrayEquals = require('uint8arrays/equals')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
require('node-forge/lib/sha512')
|
||||||
|
require('node-forge/lib/ed25519')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
|
||||||
|
const crypto = require('./rsa')
|
||||||
|
const pbm = protobuf(require('./keys.proto'))
|
||||||
|
const exporter = require('./exporter')
|
||||||
|
|
||||||
|
class RsaPublicKey {
|
||||||
|
constructor (key) {
|
||||||
|
this._key = key
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify (data, sig) { // eslint-disable-line require-await
|
||||||
|
return crypto.hashAndVerify(this._key, sig, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal () {
|
||||||
|
return crypto.utils.jwkToPkix(this._key)
|
||||||
|
}
|
||||||
|
|
||||||
|
get bytes () {
|
||||||
|
return pbm.PublicKey.encode({
|
||||||
|
Type: pbm.KeyType.RSA,
|
||||||
|
Data: this.marshal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypt (bytes) {
|
||||||
|
return crypto.encrypt(this._key, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
equals (key) {
|
||||||
|
return uint8ArrayEquals(this.bytes, key.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
async hash () { // eslint-disable-line require-await
|
||||||
|
return sha.multihashing(this.bytes, 'sha2-256')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RsaPrivateKey {
|
||||||
|
// key - Object of the jwk format
|
||||||
|
// publicKey - Uint8Array of the spki format
|
||||||
|
constructor (key, publicKey) {
|
||||||
|
this._key = key
|
||||||
|
this._publicKey = publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
genSecret () {
|
||||||
|
return crypto.getRandomValues(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
async sign (message) { // eslint-disable-line require-await
|
||||||
|
return crypto.hashAndSign(this._key, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
get public () {
|
||||||
|
if (!this._publicKey) {
|
||||||
|
throw errcode(new Error('public key not provided'), 'ERR_PUBKEY_NOT_PROVIDED')
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RsaPublicKey(this._publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt (bytes) {
|
||||||
|
return crypto.decrypt(this._key, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal () {
|
||||||
|
return crypto.utils.jwkToPkcs1(this._key)
|
||||||
|
}
|
||||||
|
|
||||||
|
get bytes () {
|
||||||
|
return pbm.PrivateKey.encode({
|
||||||
|
Type: pbm.KeyType.RSA,
|
||||||
|
Data: this.marshal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
equals (key) {
|
||||||
|
return uint8ArrayEquals(this.bytes, key.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
async hash () { // eslint-disable-line require-await
|
||||||
|
return sha.multihashing(this.bytes, 'sha2-256')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID of the key.
|
||||||
|
*
|
||||||
|
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
|
||||||
|
* The public key is a protobuf encoding containing a type and the DER encoding
|
||||||
|
* of the PKCS SubjectPublicKeyInfo.
|
||||||
|
*
|
||||||
|
* @returns {Promise<String>}
|
||||||
|
*/
|
||||||
|
async id () {
|
||||||
|
const hash = await this.public.hash()
|
||||||
|
return uint8ArrayToString(hash, 'base58btc')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the key into a password protected PEM format
|
||||||
|
*
|
||||||
|
* @param {string} password - The password to read the encrypted PEM
|
||||||
|
* @param {string} [format=pkcs-8] - The format in which to export as
|
||||||
|
*/
|
||||||
|
async export (password, format = 'pkcs-8') { // eslint-disable-line require-await
|
||||||
|
if (format === 'pkcs-8') {
|
||||||
|
const buffer = new forge.util.ByteBuffer(this.marshal())
|
||||||
|
const asn1 = forge.asn1.fromDer(buffer)
|
||||||
|
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
algorithm: 'aes256',
|
||||||
|
count: 10000,
|
||||||
|
saltSize: 128 / 8,
|
||||||
|
prfAlgorithm: 'sha512'
|
||||||
|
}
|
||||||
|
return forge.pki.encryptRsaPrivateKey(privateKey, password, options)
|
||||||
|
} else if (format === 'libp2p-key') {
|
||||||
|
return exporter.export(this.bytes, password)
|
||||||
|
} else {
|
||||||
|
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unmarshalRsaPrivateKey (bytes) {
|
||||||
|
const jwk = crypto.utils.pkcs1ToJwk(bytes)
|
||||||
|
const keys = await crypto.unmarshalPrivateKey(jwk)
|
||||||
|
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalRsaPublicKey (bytes) {
|
||||||
|
const jwk = crypto.utils.pkixToJwk(bytes)
|
||||||
|
return new RsaPublicKey(jwk)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fromJwk (jwk) {
|
||||||
|
const keys = await crypto.unmarshalPrivateKey(jwk)
|
||||||
|
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateKeyPair (bits) {
|
||||||
|
const keys = await crypto.generateKey(bits)
|
||||||
|
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
RsaPublicKey,
|
||||||
|
RsaPrivateKey,
|
||||||
|
unmarshalRsaPublicKey,
|
||||||
|
unmarshalRsaPrivateKey,
|
||||||
|
generateKeyPair,
|
||||||
|
fromJwk
|
||||||
|
}
|
69
src/keys/rsa-utils.js
Normal file
69
src/keys/rsa-utils.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
require('node-forge/lib/asn1')
|
||||||
|
require('node-forge/lib/rsa')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
const { bigIntegerToUintBase64url, base64urlToBigInteger } = require('./../util')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
// Convert a PKCS#1 in ASN1 DER format to a JWK key
|
||||||
|
exports.pkcs1ToJwk = function (bytes) {
|
||||||
|
const asn1 = forge.asn1.fromDer(uint8ArrayToString(bytes, 'ascii'))
|
||||||
|
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc7518#section-6.3.1
|
||||||
|
return {
|
||||||
|
kty: 'RSA',
|
||||||
|
n: bigIntegerToUintBase64url(privateKey.n),
|
||||||
|
e: bigIntegerToUintBase64url(privateKey.e),
|
||||||
|
d: bigIntegerToUintBase64url(privateKey.d),
|
||||||
|
p: bigIntegerToUintBase64url(privateKey.p),
|
||||||
|
q: bigIntegerToUintBase64url(privateKey.q),
|
||||||
|
dp: bigIntegerToUintBase64url(privateKey.dP),
|
||||||
|
dq: bigIntegerToUintBase64url(privateKey.dQ),
|
||||||
|
qi: bigIntegerToUintBase64url(privateKey.qInv),
|
||||||
|
alg: 'RS256',
|
||||||
|
kid: '2011-04-29'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a JWK key into PKCS#1 in ASN1 DER format
|
||||||
|
exports.jwkToPkcs1 = function (jwk) {
|
||||||
|
const asn1 = forge.pki.privateKeyToAsn1({
|
||||||
|
n: base64urlToBigInteger(jwk.n),
|
||||||
|
e: base64urlToBigInteger(jwk.e),
|
||||||
|
d: base64urlToBigInteger(jwk.d),
|
||||||
|
p: base64urlToBigInteger(jwk.p),
|
||||||
|
q: base64urlToBigInteger(jwk.q),
|
||||||
|
dP: base64urlToBigInteger(jwk.dp),
|
||||||
|
dQ: base64urlToBigInteger(jwk.dq),
|
||||||
|
qInv: base64urlToBigInteger(jwk.qi)
|
||||||
|
})
|
||||||
|
|
||||||
|
return uint8ArrayFromString(forge.asn1.toDer(asn1).getBytes(), 'ascii')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a PKCIX in ASN1 DER format to a JWK key
|
||||||
|
exports.pkixToJwk = function (bytes) {
|
||||||
|
const asn1 = forge.asn1.fromDer(uint8ArrayToString(bytes, 'ascii'))
|
||||||
|
const publicKey = forge.pki.publicKeyFromAsn1(asn1)
|
||||||
|
|
||||||
|
return {
|
||||||
|
kty: 'RSA',
|
||||||
|
n: bigIntegerToUintBase64url(publicKey.n),
|
||||||
|
e: bigIntegerToUintBase64url(publicKey.e),
|
||||||
|
alg: 'RS256',
|
||||||
|
kid: '2011-04-29'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a JWK key to PKCIX in ASN1 DER format
|
||||||
|
exports.jwkToPkix = function (jwk) {
|
||||||
|
const asn1 = forge.pki.publicKeyToAsn1({
|
||||||
|
n: base64urlToBigInteger(jwk.n),
|
||||||
|
e: base64urlToBigInteger(jwk.e)
|
||||||
|
})
|
||||||
|
|
||||||
|
return uint8ArrayFromString(forge.asn1.toDer(asn1).getBytes(), 'ascii')
|
||||||
|
}
|
182
src/keys/rsa.js
182
src/keys/rsa.js
@@ -1,133 +1,83 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const multihashing = require('multihashing-async')
|
const crypto = require('crypto')
|
||||||
const protobuf = require('protocol-buffers')
|
const errcode = require('err-code')
|
||||||
|
const randomBytes = require('../random-bytes')
|
||||||
const crypto = require('../crypto').rsa
|
// @ts-check
|
||||||
const pbm = protobuf(require('../crypto.proto'))
|
/**
|
||||||
|
* @type {PrivateKey}
|
||||||
class RsaPublicKey {
|
*/
|
||||||
constructor (key) {
|
let keypair
|
||||||
this._key = key
|
try {
|
||||||
|
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'keypair') {
|
||||||
|
throw new Error('Force keypair usage')
|
||||||
}
|
}
|
||||||
|
|
||||||
verify (data, sig, callback) {
|
const ursa = require('ursa-optional') // throws if not compiled
|
||||||
ensure(callback)
|
keypair = ({ bits }) => {
|
||||||
crypto.hashAndVerify(this._key, sig, data, callback)
|
const key = ursa.generatePrivateKey(bits)
|
||||||
}
|
return {
|
||||||
|
private: key.toPrivatePem(),
|
||||||
marshal () {
|
public: key.toPublicPem()
|
||||||
return crypto.jwkToPkix(this._key)
|
|
||||||
}
|
|
||||||
|
|
||||||
get bytes () {
|
|
||||||
return pbm.PublicKey.encode({
|
|
||||||
Type: pbm.KeyType.RSA,
|
|
||||||
Data: this.marshal()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypt (bytes) {
|
|
||||||
return this._key.encrypt(bytes, 'RSAES-PKCS1-V1_5')
|
|
||||||
}
|
|
||||||
|
|
||||||
equals (key) {
|
|
||||||
return this.bytes.equals(key.bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
hash (callback) {
|
|
||||||
ensure(callback)
|
|
||||||
multihashing(this.bytes, 'sha2-256', callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RsaPrivateKey {
|
|
||||||
// key - Object of the jwk format
|
|
||||||
// publicKey - Buffer of the spki format
|
|
||||||
constructor (key, publicKey) {
|
|
||||||
this._key = key
|
|
||||||
this._publicKey = publicKey
|
|
||||||
}
|
|
||||||
|
|
||||||
genSecret () {
|
|
||||||
return crypto.getRandomValues(new Uint8Array(16))
|
|
||||||
}
|
|
||||||
|
|
||||||
sign (message, callback) {
|
|
||||||
ensure(callback)
|
|
||||||
crypto.hashAndSign(this._key, message, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
get public () {
|
|
||||||
if (!this._publicKey) {
|
|
||||||
throw new Error('public key not provided')
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return new RsaPublicKey(this._publicKey)
|
} catch (e) {
|
||||||
|
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'ursa') {
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt (msg, callback) {
|
keypair = require('keypair')
|
||||||
crypto.decrypt(this._key, msg, callback)
|
}
|
||||||
}
|
const pemToJwk = require('pem-jwk').pem2jwk
|
||||||
|
const jwkToPem = require('pem-jwk').jwk2pem
|
||||||
|
|
||||||
marshal () {
|
exports.utils = require('./rsa-utils')
|
||||||
return crypto.jwkToPkcs1(this._key)
|
|
||||||
}
|
|
||||||
|
|
||||||
get bytes () {
|
exports.generateKey = async function (bits) { // eslint-disable-line require-await
|
||||||
return pbm.PrivateKey.encode({
|
const key = keypair({ bits })
|
||||||
Type: pbm.KeyType.RSA,
|
return {
|
||||||
Data: this.marshal()
|
privateKey: pemToJwk(key.private),
|
||||||
})
|
publicKey: pemToJwk(key.public)
|
||||||
}
|
|
||||||
|
|
||||||
equals (key) {
|
|
||||||
return this.bytes.equals(key.bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
hash (callback) {
|
|
||||||
ensure(callback)
|
|
||||||
multihashing(this.bytes, 'sha2-256', callback)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalRsaPrivateKey (bytes, callback) {
|
// Takes a jwk key
|
||||||
const jwk = crypto.pkcs1ToJwk(bytes)
|
exports.unmarshalPrivateKey = async function (key) { // eslint-disable-line require-await
|
||||||
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
|
if (!key) {
|
||||||
if (err) {
|
throw errcode(new Error('Missing key parameter'), 'ERR_MISSING_KEY')
|
||||||
return callback(err)
|
}
|
||||||
|
return {
|
||||||
|
privateKey: key,
|
||||||
|
publicKey: {
|
||||||
|
kty: key.kty,
|
||||||
|
n: key.n,
|
||||||
|
e: key.e
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function unmarshalRsaPublicKey (bytes) {
|
|
||||||
const jwk = crypto.pkixToJwk(bytes)
|
|
||||||
|
|
||||||
return new RsaPublicKey(jwk)
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateKeyPair (bits, cb) {
|
|
||||||
crypto.generateKey(bits, (err, keys) => {
|
|
||||||
if (err) {
|
|
||||||
return cb(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensure (cb) {
|
|
||||||
if (typeof cb !== 'function') {
|
|
||||||
throw new Error('callback is required')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
exports.getRandomValues = randomBytes
|
||||||
RsaPublicKey,
|
|
||||||
RsaPrivateKey,
|
exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
|
||||||
unmarshalRsaPublicKey,
|
const sign = crypto.createSign('RSA-SHA256')
|
||||||
unmarshalRsaPrivateKey,
|
sign.update(msg)
|
||||||
generateKeyPair
|
const pem = jwkToPem(key)
|
||||||
|
return sign.sign(pem)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await
|
||||||
|
const verify = crypto.createVerify('RSA-SHA256')
|
||||||
|
verify.update(msg)
|
||||||
|
const pem = jwkToPem(key)
|
||||||
|
return verify.verify(pem, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
const padding = crypto.constants.RSA_PKCS1_PADDING
|
||||||
|
|
||||||
|
exports.encrypt = function (key, bytes) {
|
||||||
|
return crypto.publicEncrypt({ key: jwkToPem(key), padding }, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.decrypt = function (key, bytes) {
|
||||||
|
return crypto.privateDecrypt({ key: jwkToPem(key), padding }, bytes)
|
||||||
}
|
}
|
||||||
|
128
src/keys/secp256k1-class.js
Normal file
128
src/keys/secp256k1-class.js
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const sha = require('multihashing-async/src/sha')
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const uint8ArrayEquals = require('uint8arrays/equals')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
|
||||||
|
const exporter = require('./exporter')
|
||||||
|
|
||||||
|
module.exports = (keysProtobuf, randomBytes, crypto) => {
|
||||||
|
crypto = crypto || require('./secp256k1')(randomBytes)
|
||||||
|
|
||||||
|
class Secp256k1PublicKey {
|
||||||
|
constructor (key) {
|
||||||
|
crypto.validatePublicKey(key)
|
||||||
|
this._key = key
|
||||||
|
}
|
||||||
|
|
||||||
|
verify (data, sig) {
|
||||||
|
return crypto.hashAndVerify(this._key, sig, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal () {
|
||||||
|
return crypto.compressPublicKey(this._key)
|
||||||
|
}
|
||||||
|
|
||||||
|
get bytes () {
|
||||||
|
return keysProtobuf.PublicKey.encode({
|
||||||
|
Type: keysProtobuf.KeyType.Secp256k1,
|
||||||
|
Data: this.marshal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
equals (key) {
|
||||||
|
return uint8ArrayEquals(this.bytes, key.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
hash () {
|
||||||
|
return sha.multihashing(this.bytes, 'sha2-256')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Secp256k1PrivateKey {
|
||||||
|
constructor (key, publicKey) {
|
||||||
|
this._key = key
|
||||||
|
this._publicKey = publicKey || crypto.computePublicKey(key)
|
||||||
|
crypto.validatePrivateKey(this._key)
|
||||||
|
crypto.validatePublicKey(this._publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
sign (message) {
|
||||||
|
return crypto.hashAndSign(this._key, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
get public () {
|
||||||
|
return new Secp256k1PublicKey(this._publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal () {
|
||||||
|
return this._key
|
||||||
|
}
|
||||||
|
|
||||||
|
get bytes () {
|
||||||
|
return keysProtobuf.PrivateKey.encode({
|
||||||
|
Type: keysProtobuf.KeyType.Secp256k1,
|
||||||
|
Data: this.marshal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
equals (key) {
|
||||||
|
return uint8ArrayEquals(this.bytes, key.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
hash () {
|
||||||
|
return sha.multihashing(this.bytes, 'sha2-256')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID of the key.
|
||||||
|
*
|
||||||
|
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
|
||||||
|
* The public key is a protobuf encoding containing a type and the DER encoding
|
||||||
|
* of the PKCS SubjectPublicKeyInfo.
|
||||||
|
*
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async id () {
|
||||||
|
const hash = await this.public.hash()
|
||||||
|
return uint8ArrayToString(hash, 'base58btc')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the key into a password protected `format`
|
||||||
|
*
|
||||||
|
* @param {string} password - The password to encrypt the key
|
||||||
|
* @param {string} [format=libp2p-key] - The format in which to export as
|
||||||
|
* @returns {Promise<string>} The encrypted private key
|
||||||
|
*/
|
||||||
|
async export (password, format = 'libp2p-key') { // eslint-disable-line require-await
|
||||||
|
if (format === 'libp2p-key') {
|
||||||
|
return exporter.export(this.bytes, password)
|
||||||
|
} else {
|
||||||
|
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalSecp256k1PrivateKey (bytes) {
|
||||||
|
return new Secp256k1PrivateKey(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
function unmarshalSecp256k1PublicKey (bytes) {
|
||||||
|
return new Secp256k1PublicKey(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateKeyPair () {
|
||||||
|
const privateKeyBytes = await crypto.generateKey()
|
||||||
|
return new Secp256k1PrivateKey(privateKeyBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Secp256k1PublicKey,
|
||||||
|
Secp256k1PrivateKey,
|
||||||
|
unmarshalSecp256k1PrivateKey,
|
||||||
|
unmarshalSecp256k1PublicKey,
|
||||||
|
generateKeyPair
|
||||||
|
}
|
||||||
|
}
|
69
src/keys/secp256k1.js
Normal file
69
src/keys/secp256k1.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const secp256k1 = require('secp256k1')
|
||||||
|
const sha = require('multihashing-async/src/sha')
|
||||||
|
const HASH_ALGORITHM = 'sha2-256'
|
||||||
|
|
||||||
|
module.exports = (randomBytes) => {
|
||||||
|
const privateKeyLength = 32
|
||||||
|
|
||||||
|
function generateKey () {
|
||||||
|
let privateKey
|
||||||
|
do {
|
||||||
|
privateKey = randomBytes(32)
|
||||||
|
} while (!secp256k1.privateKeyVerify(privateKey))
|
||||||
|
return privateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hashAndSign (key, msg) {
|
||||||
|
const digest = await sha.digest(msg, HASH_ALGORITHM)
|
||||||
|
const sig = secp256k1.ecdsaSign(digest, key)
|
||||||
|
return secp256k1.signatureExport(sig.signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hashAndVerify (key, sig, msg) {
|
||||||
|
const digest = await sha.digest(msg, HASH_ALGORITHM)
|
||||||
|
sig = secp256k1.signatureImport(sig)
|
||||||
|
return secp256k1.ecdsaVerify(sig, digest, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
function compressPublicKey (key) {
|
||||||
|
if (!secp256k1.publicKeyVerify(key)) {
|
||||||
|
throw new Error('Invalid public key')
|
||||||
|
}
|
||||||
|
return secp256k1.publicKeyConvert(key, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function decompressPublicKey (key) {
|
||||||
|
return secp256k1.publicKeyConvert(key, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePrivateKey (key) {
|
||||||
|
if (!secp256k1.privateKeyVerify(key)) {
|
||||||
|
throw new Error('Invalid private key')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePublicKey (key) {
|
||||||
|
if (!secp256k1.publicKeyVerify(key)) {
|
||||||
|
throw new Error('Invalid public key')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computePublicKey (privateKey) {
|
||||||
|
validatePrivateKey(privateKey)
|
||||||
|
return secp256k1.publicKeyCreate(privateKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
generateKey,
|
||||||
|
privateKeyLength,
|
||||||
|
hashAndSign,
|
||||||
|
hashAndVerify,
|
||||||
|
compressPublicKey,
|
||||||
|
decompressPublicKey,
|
||||||
|
validatePrivateKey,
|
||||||
|
validatePublicKey,
|
||||||
|
computePublicKey
|
||||||
|
}
|
||||||
|
}
|
10
src/keys/validate-curve-type.js
Normal file
10
src/keys/validate-curve-type.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
|
||||||
|
module.exports = function (curveTypes, type) {
|
||||||
|
if (!curveTypes.includes(type)) {
|
||||||
|
const names = curveTypes.join(' / ')
|
||||||
|
throw errcode(new Error(`Unknown curve: ${type}. Must be ${names}`), 'ERR_INVALID_CURVE')
|
||||||
|
}
|
||||||
|
}
|
45
src/pbkdf2.js
Normal file
45
src/pbkdf2.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const forgePbkdf2 = require('node-forge/lib/pbkdf2')
|
||||||
|
const forgeUtil = require('node-forge/lib/util')
|
||||||
|
const errcode = require('err-code')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps an IPFS hash name to its node-forge equivalent.
|
||||||
|
*
|
||||||
|
* See https://github.com/multiformats/multihash/blob/master/hashtable.csv
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const hashName = {
|
||||||
|
sha1: 'sha1',
|
||||||
|
'sha2-256': 'sha256',
|
||||||
|
'sha2-512': 'sha512'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the Password-Based Key Derivation Function 2.
|
||||||
|
*
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} salt
|
||||||
|
* @param {number} iterations
|
||||||
|
* @param {number} keySize (in bytes)
|
||||||
|
* @param {string} hash - The hash name ('sha1', 'sha2-512, ...)
|
||||||
|
* @returns {string} - A new password
|
||||||
|
*/
|
||||||
|
function pbkdf2 (password, salt, iterations, keySize, hash) {
|
||||||
|
const hasher = hashName[hash]
|
||||||
|
if (!hasher) {
|
||||||
|
const types = Object.keys(hashName).join(' / ')
|
||||||
|
throw errcode(new Error(`Hash '${hash}' is unknown or not supported. Must be ${types}`), 'ERR_UNSUPPORTED_HASH_TYPE')
|
||||||
|
}
|
||||||
|
const dek = forgePbkdf2(
|
||||||
|
password,
|
||||||
|
salt,
|
||||||
|
iterations,
|
||||||
|
keySize,
|
||||||
|
hasher)
|
||||||
|
return forgeUtil.encode64(dek)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = pbkdf2
|
10
src/random-bytes.js
Normal file
10
src/random-bytes.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict'
|
||||||
|
const randomBytes = require('iso-random-stream/src/random')
|
||||||
|
const errcode = require('err-code')
|
||||||
|
|
||||||
|
module.exports = function (length) {
|
||||||
|
if (isNaN(length) || length <= 0) {
|
||||||
|
throw errcode(new Error('random bytes length must be a Number bigger than 0'), 'ERR_INVALID_LENGTH')
|
||||||
|
}
|
||||||
|
return randomBytes(length)
|
||||||
|
}
|
43
src/util.js
Normal file
43
src/util.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
require('node-forge/lib/util')
|
||||||
|
require('node-forge/lib/jsbn')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||||
|
const uint8ArrayConcat = require('uint8arrays/concat')
|
||||||
|
|
||||||
|
exports.bigIntegerToUintBase64url = (num, len) => {
|
||||||
|
// Call `.abs()` to convert to unsigned
|
||||||
|
let buf = Uint8Array.from(num.abs().toByteArray()) // toByteArray converts to big endian
|
||||||
|
|
||||||
|
// toByteArray() gives us back a signed array, which will include a leading 0
|
||||||
|
// byte if the most significant bit of the number is 1:
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/seccertenroll/about-integer
|
||||||
|
// Our number will always be positive so we should remove the leading padding.
|
||||||
|
buf = buf[0] === 0 ? buf.slice(1) : buf
|
||||||
|
|
||||||
|
if (len != null) {
|
||||||
|
if (buf.length > len) throw new Error('byte array longer than desired length')
|
||||||
|
buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf])
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint8ArrayToString(buf, 'base64url')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a base64url encoded string to a BigInteger
|
||||||
|
exports.base64urlToBigInteger = str => {
|
||||||
|
const buf = exports.base64urlToBuffer(str)
|
||||||
|
return new forge.jsbn.BigInteger(uint8ArrayToString(buf, 'base16'), 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.base64urlToBuffer = (str, len) => {
|
||||||
|
let buf = uint8ArrayFromString(str, 'base64urlpad')
|
||||||
|
|
||||||
|
if (len != null) {
|
||||||
|
if (buf.length > len) throw new Error('byte array longer than desired length')
|
||||||
|
buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf])
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
24
src/webcrypto.js
Normal file
24
src/webcrypto.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/* eslint-env browser */
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
// Check native crypto exists and is enabled (In insecure context `self.crypto`
|
||||||
|
// exists but `self.crypto.subtle` does not).
|
||||||
|
exports.get = (win = self) => {
|
||||||
|
const nativeCrypto = win.crypto || win.msCrypto
|
||||||
|
|
||||||
|
if (!nativeCrypto || !nativeCrypto.subtle) {
|
||||||
|
throw Object.assign(
|
||||||
|
new Error(
|
||||||
|
'Missing Web Crypto API. ' +
|
||||||
|
'The most likely cause of this error is that this page is being accessed ' +
|
||||||
|
'from an insecure context (i.e. not HTTPS). For more information and ' +
|
||||||
|
'possible resolutions see ' +
|
||||||
|
'https://github.com/libp2p/js-libp2p-crypto/blob/master/README.md#web-crypto-api'
|
||||||
|
),
|
||||||
|
{ code: 'ERR_MISSING_WEB_CRYPTO' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nativeCrypto
|
||||||
|
}
|
@@ -1,37 +0,0 @@
|
|||||||
/* eslint max-nested-callbacks: ["error", 8] */
|
|
||||||
/* eslint-env mocha */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect
|
|
||||||
const crypto = require('../src')
|
|
||||||
|
|
||||||
const bytes = {
|
|
||||||
16: 'AES-128',
|
|
||||||
32: 'AES-256'
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('AES-CTR', () => {
|
|
||||||
Object.keys(bytes).forEach((byte) => {
|
|
||||||
it(`${bytes[byte]} - encrypt and decrypt`, (done) => {
|
|
||||||
const key = new Buffer(parseInt(byte, 10))
|
|
||||||
key.fill(5)
|
|
||||||
|
|
||||||
const iv = new Buffer(16)
|
|
||||||
iv.fill(1)
|
|
||||||
|
|
||||||
crypto.aes.create(key, iv, (err, cipher) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
|
|
||||||
cipher.encrypt(new Buffer('hello'), (err, res) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
|
|
||||||
cipher.decrypt(res, (err, res) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
expect(res).to.be.eql(new Buffer('hello'))
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
111
test/aes/aes.spec.js
Normal file
111
test/aes/aes.spec.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-disable valid-jsdoc */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
const { expectErrCode } = require('../util')
|
||||||
|
|
||||||
|
const crypto = require('../../src')
|
||||||
|
const fixtures = require('./../fixtures/aes')
|
||||||
|
const goFixtures = require('./../fixtures/go-aes')
|
||||||
|
|
||||||
|
const bytes = {
|
||||||
|
16: 'AES-128',
|
||||||
|
32: 'AES-256'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @typedef {import("libp2p-crypto").aes.Cipher} Cipher */
|
||||||
|
|
||||||
|
describe('AES-CTR', () => {
|
||||||
|
Object.keys(bytes).forEach((byte) => {
|
||||||
|
it(`${bytes[byte]} - encrypt and decrypt`, async () => {
|
||||||
|
const key = new Uint8Array(parseInt(byte, 10))
|
||||||
|
key.fill(5)
|
||||||
|
|
||||||
|
const iv = new Uint8Array(16)
|
||||||
|
iv.fill(1)
|
||||||
|
|
||||||
|
const cipher = await crypto.aes.create(key, iv)
|
||||||
|
|
||||||
|
await encryptAndDecrypt(cipher)
|
||||||
|
await encryptAndDecrypt(cipher)
|
||||||
|
await encryptAndDecrypt(cipher)
|
||||||
|
await encryptAndDecrypt(cipher)
|
||||||
|
await encryptAndDecrypt(cipher)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.keys(bytes).forEach((byte) => {
|
||||||
|
it(`${bytes[byte]} - fixed - encrypt and decrypt`, async () => {
|
||||||
|
const key = new Uint8Array(parseInt(byte, 10))
|
||||||
|
key.fill(5)
|
||||||
|
|
||||||
|
const iv = new Uint8Array(16)
|
||||||
|
iv.fill(1)
|
||||||
|
|
||||||
|
const cipher = await crypto.aes.create(key, iv)
|
||||||
|
|
||||||
|
for (let i = 0; i < fixtures[byte].inputs.length; i++) {
|
||||||
|
const rawIn = fixtures[byte].inputs[i]
|
||||||
|
const input = Uint8Array.from(rawIn.data)
|
||||||
|
const output = Uint8Array.from(fixtures[byte].outputs[i].data)
|
||||||
|
const encrypted = await cipher.encrypt(input)
|
||||||
|
expect(encrypted).to.have.length(output.length)
|
||||||
|
expect(encrypted).to.eql(output)
|
||||||
|
const decrypted = await cipher.decrypt(encrypted)
|
||||||
|
expect(decrypted).to.eql(input)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.keys(bytes).forEach((byte) => {
|
||||||
|
if (!goFixtures[byte]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
it(`${bytes[byte]} - go interop - encrypt and decrypt`, async () => {
|
||||||
|
const key = new Uint8Array(parseInt(byte, 10))
|
||||||
|
key.fill(5)
|
||||||
|
|
||||||
|
const iv = new Uint8Array(16)
|
||||||
|
iv.fill(1)
|
||||||
|
|
||||||
|
const cipher = await crypto.aes.create(key, iv)
|
||||||
|
|
||||||
|
for (let i = 0; i < goFixtures[byte].inputs.length; i++) {
|
||||||
|
const rawIn = goFixtures[byte].inputs[i]
|
||||||
|
const input = Uint8Array.from(rawIn)
|
||||||
|
const output = Uint8Array.from(goFixtures[byte].outputs[i])
|
||||||
|
const encrypted = await cipher.encrypt(input)
|
||||||
|
expect(encrypted).to.have.length(output.length)
|
||||||
|
expect(encrypted).to.eql(output)
|
||||||
|
const decrypted = await cipher.decrypt(encrypted)
|
||||||
|
expect(decrypted).to.eql(input)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('checks key length', () => {
|
||||||
|
const key = new Uint8Array(5)
|
||||||
|
const iv = new Uint8Array(16)
|
||||||
|
return expectErrCode(crypto.aes.create(key, iv), 'ERR_INVALID_KEY_LENGTH')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {function(Cipher): Promise<void>}
|
||||||
|
*/
|
||||||
|
async function encryptAndDecrypt (cipher) {
|
||||||
|
const data = new Uint8Array(100)
|
||||||
|
data.fill(Math.ceil(Math.random() * 100))
|
||||||
|
|
||||||
|
const encrypted = await cipher.encrypt(data)
|
||||||
|
const decrypted = await cipher.decrypt(encrypted)
|
||||||
|
|
||||||
|
expect(decrypted).to.be.eql(data)
|
||||||
|
}
|
62
test/browser.js
Normal file
62
test/browser.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
chai.use(require('dirty-chai'))
|
||||||
|
const expect = chai.expect
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
const crypto = require('../')
|
||||||
|
const webcrypto = require('../src/webcrypto')
|
||||||
|
|
||||||
|
async function expectMissingWebCrypto (fn) {
|
||||||
|
try {
|
||||||
|
await fn()
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.code).to.equal('ERR_MISSING_WEB_CRYPTO')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
throw new Error('Expected missing web crypto error')
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Missing web crypto', () => {
|
||||||
|
let webcryptoGet
|
||||||
|
let rsaPrivateKey
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
rsaPrivateKey = await crypto.keys.generateKeyPair('RSA', 512)
|
||||||
|
})
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
webcryptoGet = webcrypto.get
|
||||||
|
webcrypto.get = () => webcryptoGet({})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
webcrypto.get = webcryptoGet
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should error for hmac create when web crypto is missing', () => {
|
||||||
|
return expectMissingWebCrypto(() => crypto.hmac.create('SHA256', uint8ArrayFromString('secret')))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should error for generate ephemeral key pair when web crypto is missing', () => {
|
||||||
|
return expectMissingWebCrypto(() => crypto.keys.generateEphemeralKeyPair('P-256'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should error for generate rsa key pair when web crypto is missing', () => {
|
||||||
|
return expectMissingWebCrypto(() => crypto.keys.generateKeyPair('rsa', 256))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should error for unmarshal RSA private key when web crypto is missing', () => {
|
||||||
|
return expectMissingWebCrypto(() => crypto.keys.unmarshalPrivateKey(crypto.keys.marshalPrivateKey(rsaPrivateKey)))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should error for sign RSA private key when web crypto is missing', () => {
|
||||||
|
return expectMissingWebCrypto(() => rsaPrivateKey.sign(uint8ArrayFromString('test')))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should error for verify RSA public key when web crypto is missing', () => {
|
||||||
|
return expectMissingWebCrypto(() => rsaPrivateKey.public.verify(uint8ArrayFromString('test'), uint8ArrayFromString('test')))
|
||||||
|
})
|
||||||
|
})
|
132
test/crypto.spec.js
Normal file
132
test/crypto.spec.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
const crypto = require('../src')
|
||||||
|
const fixtures = require('./fixtures/go-key-rsa')
|
||||||
|
const { expectErrCode } = require('./util')
|
||||||
|
const uint8ArrayEquals = require('uint8arrays/equals')
|
||||||
|
|
||||||
|
/** @typedef {import("libp2p-crypto").PrivateKey} PrivateKey */
|
||||||
|
|
||||||
|
describe('libp2p-crypto', function () {
|
||||||
|
this.timeout(20 * 1000)
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {PrivateKey}
|
||||||
|
*/
|
||||||
|
let key
|
||||||
|
before(async () => {
|
||||||
|
key = await crypto.keys.generateKeyPair('RSA', 512)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('marshalPublicKey and unmarshalPublicKey', () => {
|
||||||
|
const key2 = crypto.keys.unmarshalPublicKey(
|
||||||
|
crypto.keys.marshalPublicKey(key.public))
|
||||||
|
|
||||||
|
expect(key2.equals(key.public)).to.be.eql(true)
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
crypto.keys.marshalPublicKey(key.public, 'invalid-key-type')
|
||||||
|
}).to.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('marshalPrivateKey and unmarshalPrivateKey', async () => {
|
||||||
|
expect(() => {
|
||||||
|
crypto.keys.marshalPrivateKey(key, 'invalid-key-type')
|
||||||
|
}).to.throw()
|
||||||
|
|
||||||
|
const key2 = await crypto.keys.unmarshalPrivateKey(crypto.keys.marshalPrivateKey(key))
|
||||||
|
|
||||||
|
expect(key2.equals(key)).to.be.eql(true)
|
||||||
|
expect(key2.public.equals(key.public)).to.be.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generateKeyPair', () => {
|
||||||
|
return expectErrCode(crypto.keys.generateKeyPair('invalid-key-type', 512), 'ERR_UNSUPPORTED_KEY_TYPE')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generateKeyPairFromSeed', () => {
|
||||||
|
var seed = crypto.randomBytes(32)
|
||||||
|
return expectErrCode(crypto.keys.generateKeyPairFromSeed('invalid-key-type', seed, 512), 'ERR_UNSUPPORTED_KEY_TYPE')
|
||||||
|
})
|
||||||
|
|
||||||
|
// marshalled keys seem to be slightly different
|
||||||
|
// unsure as to if this is just a difference in encoding
|
||||||
|
// or a bug
|
||||||
|
describe('go interop', () => {
|
||||||
|
it('unmarshals private key', async () => {
|
||||||
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.private.key)
|
||||||
|
const hash = fixtures.private.hash
|
||||||
|
expect(fixtures.private.key).to.eql(key.bytes)
|
||||||
|
const digest = await key.hash()
|
||||||
|
expect(digest).to.eql(hash)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('unmarshals public key', async () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.public.key)
|
||||||
|
const hash = fixtures.public.hash
|
||||||
|
expect(crypto.keys.marshalPublicKey(key)).to.eql(fixtures.public.key)
|
||||||
|
const digest = await key.hash()
|
||||||
|
expect(digest).to.eql(hash)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('unmarshal -> marshal, private key', async () => {
|
||||||
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.private.key)
|
||||||
|
const marshalled = crypto.keys.marshalPrivateKey(key)
|
||||||
|
expect(marshalled).to.eql(fixtures.private.key)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('unmarshal -> marshal, public key', () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.public.key)
|
||||||
|
const marshalled = crypto.keys.marshalPublicKey(key)
|
||||||
|
expect(uint8ArrayEquals(fixtures.public.key, marshalled)).to.eql(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('pbkdf2', () => {
|
||||||
|
it('generates a derived password using sha1', () => {
|
||||||
|
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'sha1')
|
||||||
|
expect(p1).to.exist()
|
||||||
|
expect(p1).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a derived password using sha2-512', () => {
|
||||||
|
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'sha2-512')
|
||||||
|
expect(p1).to.exist()
|
||||||
|
expect(p1).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates the same derived password with the same options', () => {
|
||||||
|
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 10, 512 / 8, 'sha1')
|
||||||
|
const p2 = crypto.pbkdf2('password', 'at least 16 character salt', 10, 512 / 8, 'sha1')
|
||||||
|
const p3 = crypto.pbkdf2('password', 'at least 16 character salt', 11, 512 / 8, 'sha1')
|
||||||
|
expect(p2).to.equal(p1)
|
||||||
|
expect(p3).to.not.equal(p2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on invalid hash name', () => {
|
||||||
|
const fn = () => crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'shaX-xxx')
|
||||||
|
expect(fn).to.throw().with.property('code', 'ERR_UNSUPPORTED_HASH_TYPE')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('randomBytes', () => {
|
||||||
|
it('throws with invalid number passed', () => {
|
||||||
|
expect(() => {
|
||||||
|
crypto.randomBytes(-1)
|
||||||
|
}).to.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates different random things', () => {
|
||||||
|
const buf1 = crypto.randomBytes(10)
|
||||||
|
expect(buf1.length).to.equal(10)
|
||||||
|
const buf2 = crypto.randomBytes(10)
|
||||||
|
expect(buf1).to.not.eql(buf2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@@ -1,53 +0,0 @@
|
|||||||
/* eslint max-nested-callbacks: ["error", 8] */
|
|
||||||
/* eslint-env mocha */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect
|
|
||||||
const parallel = require('async/parallel')
|
|
||||||
|
|
||||||
const fixtures = require('./fixtures/go-elliptic-key')
|
|
||||||
const crypto = require('../src')
|
|
||||||
|
|
||||||
const curves = ['P-256', 'P-384'] // 'P-521' fails in tests :( no clue why
|
|
||||||
const lengths = {
|
|
||||||
'P-256': 65,
|
|
||||||
'P-384': 97,
|
|
||||||
'P-521': 133
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('generateEphemeralKeyPair', () => {
|
|
||||||
curves.forEach((curve) => {
|
|
||||||
it(`generate and shared key ${curve}`, (done) => {
|
|
||||||
parallel([
|
|
||||||
(cb) => crypto.generateEphemeralKeyPair(curve, cb),
|
|
||||||
(cb) => crypto.generateEphemeralKeyPair(curve, cb)
|
|
||||||
], (err, keys) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
expect(keys[0].key).to.have.length(lengths[curve])
|
|
||||||
expect(keys[1].key).to.have.length(lengths[curve])
|
|
||||||
|
|
||||||
keys[0].genSharedKey(keys[1].key, (err, shared) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
expect(shared).to.have.length(32)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('go interop', () => {
|
|
||||||
it('generates a shared secret', (done) => {
|
|
||||||
const curve = fixtures.curve
|
|
||||||
|
|
||||||
crypto.generateEphemeralKeyPair(curve, (err, alice) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
|
|
||||||
alice.genSharedKey(fixtures.bob.public, (err, s1) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
expect(s1).to.have.length(32)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
27
test/fixtures/aes.js
vendored
Normal file
27
test/fixtures/aes.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const fixes16 = [
|
||||||
|
require('./fix1.json'),
|
||||||
|
require('./fix2.json'),
|
||||||
|
require('./fix3.json'),
|
||||||
|
require('./fix4.json'),
|
||||||
|
require('./fix5.json')
|
||||||
|
]
|
||||||
|
const fixes32 = [
|
||||||
|
require('./fix6.json'),
|
||||||
|
require('./fix7.json'),
|
||||||
|
require('./fix8.json'),
|
||||||
|
require('./fix9.json'),
|
||||||
|
require('./fix10.json')
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
16: {
|
||||||
|
inputs: fixes16.map((f) => f.input),
|
||||||
|
outputs: fixes16.map((f) => f.output)
|
||||||
|
},
|
||||||
|
32: {
|
||||||
|
inputs: fixes32.map((f) => f.input),
|
||||||
|
outputs: fixes32.map((f) => f.output)
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix1.json
vendored
Normal file
212
test/fixtures/fix1.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47,
|
||||||
|
47
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
121,
|
||||||
|
104,
|
||||||
|
0,
|
||||||
|
151,
|
||||||
|
57,
|
||||||
|
137,
|
||||||
|
22,
|
||||||
|
239,
|
||||||
|
234,
|
||||||
|
151,
|
||||||
|
58,
|
||||||
|
15,
|
||||||
|
100,
|
||||||
|
22,
|
||||||
|
228,
|
||||||
|
110,
|
||||||
|
85,
|
||||||
|
248,
|
||||||
|
249,
|
||||||
|
15,
|
||||||
|
145,
|
||||||
|
128,
|
||||||
|
223,
|
||||||
|
25,
|
||||||
|
192,
|
||||||
|
175,
|
||||||
|
132,
|
||||||
|
169,
|
||||||
|
98,
|
||||||
|
203,
|
||||||
|
231,
|
||||||
|
106,
|
||||||
|
224,
|
||||||
|
102,
|
||||||
|
206,
|
||||||
|
244,
|
||||||
|
29,
|
||||||
|
213,
|
||||||
|
36,
|
||||||
|
2,
|
||||||
|
26,
|
||||||
|
213,
|
||||||
|
94,
|
||||||
|
29,
|
||||||
|
134,
|
||||||
|
219,
|
||||||
|
136,
|
||||||
|
73,
|
||||||
|
212,
|
||||||
|
176,
|
||||||
|
33,
|
||||||
|
95,
|
||||||
|
198,
|
||||||
|
91,
|
||||||
|
148,
|
||||||
|
139,
|
||||||
|
132,
|
||||||
|
252,
|
||||||
|
182,
|
||||||
|
115,
|
||||||
|
116,
|
||||||
|
160,
|
||||||
|
146,
|
||||||
|
194,
|
||||||
|
0,
|
||||||
|
97,
|
||||||
|
181,
|
||||||
|
0,
|
||||||
|
193,
|
||||||
|
149,
|
||||||
|
21,
|
||||||
|
51,
|
||||||
|
248,
|
||||||
|
97,
|
||||||
|
32,
|
||||||
|
62,
|
||||||
|
86,
|
||||||
|
153,
|
||||||
|
238,
|
||||||
|
67,
|
||||||
|
38,
|
||||||
|
34,
|
||||||
|
55,
|
||||||
|
143,
|
||||||
|
70,
|
||||||
|
193,
|
||||||
|
99,
|
||||||
|
107,
|
||||||
|
31,
|
||||||
|
67,
|
||||||
|
90,
|
||||||
|
97,
|
||||||
|
55,
|
||||||
|
63,
|
||||||
|
69,
|
||||||
|
203,
|
||||||
|
33,
|
||||||
|
233,
|
||||||
|
74,
|
||||||
|
237
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix10.json
vendored
Normal file
212
test/fixtures/fix10.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72,
|
||||||
|
72
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
201,
|
||||||
|
224,
|
||||||
|
56,
|
||||||
|
64,
|
||||||
|
167,
|
||||||
|
224,
|
||||||
|
124,
|
||||||
|
49,
|
||||||
|
19,
|
||||||
|
51,
|
||||||
|
208,
|
||||||
|
226,
|
||||||
|
216,
|
||||||
|
50,
|
||||||
|
12,
|
||||||
|
73,
|
||||||
|
15,
|
||||||
|
255,
|
||||||
|
156,
|
||||||
|
108,
|
||||||
|
98,
|
||||||
|
179,
|
||||||
|
144,
|
||||||
|
110,
|
||||||
|
33,
|
||||||
|
151,
|
||||||
|
43,
|
||||||
|
64,
|
||||||
|
227,
|
||||||
|
153,
|
||||||
|
120,
|
||||||
|
39,
|
||||||
|
21,
|
||||||
|
151,
|
||||||
|
41,
|
||||||
|
61,
|
||||||
|
245,
|
||||||
|
20,
|
||||||
|
31,
|
||||||
|
23,
|
||||||
|
109,
|
||||||
|
213,
|
||||||
|
109,
|
||||||
|
55,
|
||||||
|
35,
|
||||||
|
40,
|
||||||
|
122,
|
||||||
|
109,
|
||||||
|
41,
|
||||||
|
10,
|
||||||
|
32,
|
||||||
|
176,
|
||||||
|
25,
|
||||||
|
184,
|
||||||
|
91,
|
||||||
|
176,
|
||||||
|
177,
|
||||||
|
134,
|
||||||
|
138,
|
||||||
|
252,
|
||||||
|
160,
|
||||||
|
2,
|
||||||
|
108,
|
||||||
|
43,
|
||||||
|
222,
|
||||||
|
239,
|
||||||
|
174,
|
||||||
|
2,
|
||||||
|
145,
|
||||||
|
74,
|
||||||
|
34,
|
||||||
|
131,
|
||||||
|
237,
|
||||||
|
214,
|
||||||
|
235,
|
||||||
|
102,
|
||||||
|
26,
|
||||||
|
204,
|
||||||
|
124,
|
||||||
|
64,
|
||||||
|
101,
|
||||||
|
134,
|
||||||
|
186,
|
||||||
|
45,
|
||||||
|
55,
|
||||||
|
29,
|
||||||
|
52,
|
||||||
|
55,
|
||||||
|
171,
|
||||||
|
95,
|
||||||
|
172,
|
||||||
|
86,
|
||||||
|
242,
|
||||||
|
101,
|
||||||
|
141,
|
||||||
|
153,
|
||||||
|
222,
|
||||||
|
161,
|
||||||
|
128,
|
||||||
|
83
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix2.json
vendored
Normal file
212
test/fixtures/fix2.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
24
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
109,
|
||||||
|
172,
|
||||||
|
127,
|
||||||
|
179,
|
||||||
|
110,
|
||||||
|
222,
|
||||||
|
79,
|
||||||
|
219,
|
||||||
|
87,
|
||||||
|
76,
|
||||||
|
70,
|
||||||
|
204,
|
||||||
|
166,
|
||||||
|
110,
|
||||||
|
184,
|
||||||
|
229,
|
||||||
|
90,
|
||||||
|
49,
|
||||||
|
160,
|
||||||
|
252,
|
||||||
|
78,
|
||||||
|
58,
|
||||||
|
73,
|
||||||
|
51,
|
||||||
|
152,
|
||||||
|
218,
|
||||||
|
3,
|
||||||
|
200,
|
||||||
|
10,
|
||||||
|
124,
|
||||||
|
152,
|
||||||
|
117,
|
||||||
|
137,
|
||||||
|
40,
|
||||||
|
23,
|
||||||
|
127,
|
||||||
|
56,
|
||||||
|
57,
|
||||||
|
203,
|
||||||
|
31,
|
||||||
|
101,
|
||||||
|
227,
|
||||||
|
31,
|
||||||
|
198,
|
||||||
|
223,
|
||||||
|
86,
|
||||||
|
98,
|
||||||
|
120,
|
||||||
|
100,
|
||||||
|
86,
|
||||||
|
116,
|
||||||
|
144,
|
||||||
|
142,
|
||||||
|
127,
|
||||||
|
68,
|
||||||
|
175,
|
||||||
|
249,
|
||||||
|
232,
|
||||||
|
22,
|
||||||
|
83,
|
||||||
|
22,
|
||||||
|
68,
|
||||||
|
60,
|
||||||
|
230,
|
||||||
|
146,
|
||||||
|
22,
|
||||||
|
153,
|
||||||
|
193,
|
||||||
|
67,
|
||||||
|
5,
|
||||||
|
51,
|
||||||
|
253,
|
||||||
|
239,
|
||||||
|
210,
|
||||||
|
80,
|
||||||
|
31,
|
||||||
|
254,
|
||||||
|
103,
|
||||||
|
185,
|
||||||
|
145,
|
||||||
|
123,
|
||||||
|
99,
|
||||||
|
205,
|
||||||
|
175,
|
||||||
|
156,
|
||||||
|
144,
|
||||||
|
191,
|
||||||
|
67,
|
||||||
|
31,
|
||||||
|
236,
|
||||||
|
43,
|
||||||
|
98,
|
||||||
|
197,
|
||||||
|
235,
|
||||||
|
31,
|
||||||
|
50,
|
||||||
|
69,
|
||||||
|
228,
|
||||||
|
100,
|
||||||
|
64
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix3.json
vendored
Normal file
212
test/fixtures/fix3.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
191,
|
||||||
|
93,
|
||||||
|
126,
|
||||||
|
191,
|
||||||
|
180,
|
||||||
|
42,
|
||||||
|
118,
|
||||||
|
144,
|
||||||
|
28,
|
||||||
|
188,
|
||||||
|
211,
|
||||||
|
191,
|
||||||
|
211,
|
||||||
|
130,
|
||||||
|
170,
|
||||||
|
153,
|
||||||
|
134,
|
||||||
|
240,
|
||||||
|
179,
|
||||||
|
83,
|
||||||
|
75,
|
||||||
|
23,
|
||||||
|
42,
|
||||||
|
68,
|
||||||
|
158,
|
||||||
|
200,
|
||||||
|
123,
|
||||||
|
155,
|
||||||
|
57,
|
||||||
|
169,
|
||||||
|
152,
|
||||||
|
133,
|
||||||
|
33,
|
||||||
|
114,
|
||||||
|
90,
|
||||||
|
29,
|
||||||
|
131,
|
||||||
|
91,
|
||||||
|
70,
|
||||||
|
105,
|
||||||
|
83,
|
||||||
|
45,
|
||||||
|
40,
|
||||||
|
47,
|
||||||
|
77,
|
||||||
|
96,
|
||||||
|
97,
|
||||||
|
8,
|
||||||
|
40,
|
||||||
|
1,
|
||||||
|
110,
|
||||||
|
245,
|
||||||
|
106,
|
||||||
|
172,
|
||||||
|
152,
|
||||||
|
146,
|
||||||
|
5,
|
||||||
|
114,
|
||||||
|
132,
|
||||||
|
0,
|
||||||
|
179,
|
||||||
|
31,
|
||||||
|
44,
|
||||||
|
78,
|
||||||
|
19,
|
||||||
|
109,
|
||||||
|
92,
|
||||||
|
199,
|
||||||
|
226,
|
||||||
|
36,
|
||||||
|
12,
|
||||||
|
74,
|
||||||
|
180,
|
||||||
|
241,
|
||||||
|
224,
|
||||||
|
107,
|
||||||
|
83,
|
||||||
|
13,
|
||||||
|
167,
|
||||||
|
27,
|
||||||
|
251,
|
||||||
|
101,
|
||||||
|
193,
|
||||||
|
98,
|
||||||
|
49,
|
||||||
|
90,
|
||||||
|
225,
|
||||||
|
197,
|
||||||
|
75,
|
||||||
|
213,
|
||||||
|
144,
|
||||||
|
52,
|
||||||
|
235,
|
||||||
|
130,
|
||||||
|
92,
|
||||||
|
247,
|
||||||
|
219,
|
||||||
|
139,
|
||||||
|
209,
|
||||||
|
132
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix4.json
vendored
Normal file
212
test/fixtures/fix4.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
191,
|
||||||
|
110,
|
||||||
|
53,
|
||||||
|
190,
|
||||||
|
250,
|
||||||
|
44,
|
||||||
|
190,
|
||||||
|
136,
|
||||||
|
22,
|
||||||
|
209,
|
||||||
|
131,
|
||||||
|
200,
|
||||||
|
112,
|
||||||
|
31,
|
||||||
|
61,
|
||||||
|
183,
|
||||||
|
247,
|
||||||
|
95,
|
||||||
|
4,
|
||||||
|
249,
|
||||||
|
69,
|
||||||
|
147,
|
||||||
|
238,
|
||||||
|
74,
|
||||||
|
18,
|
||||||
|
71,
|
||||||
|
197,
|
||||||
|
115,
|
||||||
|
141,
|
||||||
|
226,
|
||||||
|
102,
|
||||||
|
92,
|
||||||
|
91,
|
||||||
|
128,
|
||||||
|
181,
|
||||||
|
172,
|
||||||
|
67,
|
||||||
|
109,
|
||||||
|
17,
|
||||||
|
165,
|
||||||
|
52,
|
||||||
|
10,
|
||||||
|
55,
|
||||||
|
31,
|
||||||
|
55,
|
||||||
|
225,
|
||||||
|
253,
|
||||||
|
140,
|
||||||
|
154,
|
||||||
|
35,
|
||||||
|
104,
|
||||||
|
62,
|
||||||
|
119,
|
||||||
|
103,
|
||||||
|
197,
|
||||||
|
152,
|
||||||
|
125,
|
||||||
|
134,
|
||||||
|
140,
|
||||||
|
181,
|
||||||
|
170,
|
||||||
|
76,
|
||||||
|
75,
|
||||||
|
114,
|
||||||
|
195,
|
||||||
|
188,
|
||||||
|
68,
|
||||||
|
197,
|
||||||
|
28,
|
||||||
|
47,
|
||||||
|
116,
|
||||||
|
82,
|
||||||
|
34,
|
||||||
|
128,
|
||||||
|
232,
|
||||||
|
122,
|
||||||
|
14,
|
||||||
|
229,
|
||||||
|
122,
|
||||||
|
161,
|
||||||
|
36,
|
||||||
|
212,
|
||||||
|
161,
|
||||||
|
164,
|
||||||
|
145,
|
||||||
|
86,
|
||||||
|
215,
|
||||||
|
233,
|
||||||
|
222,
|
||||||
|
50,
|
||||||
|
143,
|
||||||
|
89,
|
||||||
|
131,
|
||||||
|
32,
|
||||||
|
130,
|
||||||
|
196,
|
||||||
|
109,
|
||||||
|
36,
|
||||||
|
204,
|
||||||
|
254
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix5.json
vendored
Normal file
212
test/fixtures/fix5.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48,
|
||||||
|
48
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
97,
|
||||||
|
142,
|
||||||
|
8,
|
||||||
|
37,
|
||||||
|
69,
|
||||||
|
173,
|
||||||
|
124,
|
||||||
|
180,
|
||||||
|
97,
|
||||||
|
70,
|
||||||
|
45,
|
||||||
|
91,
|
||||||
|
196,
|
||||||
|
126,
|
||||||
|
184,
|
||||||
|
135,
|
||||||
|
213,
|
||||||
|
104,
|
||||||
|
171,
|
||||||
|
89,
|
||||||
|
231,
|
||||||
|
63,
|
||||||
|
43,
|
||||||
|
42,
|
||||||
|
7,
|
||||||
|
245,
|
||||||
|
75,
|
||||||
|
165,
|
||||||
|
205,
|
||||||
|
182,
|
||||||
|
24,
|
||||||
|
50,
|
||||||
|
170,
|
||||||
|
217,
|
||||||
|
128,
|
||||||
|
112,
|
||||||
|
114,
|
||||||
|
215,
|
||||||
|
209,
|
||||||
|
145,
|
||||||
|
135,
|
||||||
|
235,
|
||||||
|
179,
|
||||||
|
212,
|
||||||
|
5,
|
||||||
|
81,
|
||||||
|
142,
|
||||||
|
199,
|
||||||
|
53,
|
||||||
|
221,
|
||||||
|
39,
|
||||||
|
239,
|
||||||
|
167,
|
||||||
|
21,
|
||||||
|
237,
|
||||||
|
168,
|
||||||
|
145,
|
||||||
|
249,
|
||||||
|
250,
|
||||||
|
108,
|
||||||
|
2,
|
||||||
|
247,
|
||||||
|
89,
|
||||||
|
73,
|
||||||
|
228,
|
||||||
|
227,
|
||||||
|
255,
|
||||||
|
155,
|
||||||
|
121,
|
||||||
|
157,
|
||||||
|
205,
|
||||||
|
96,
|
||||||
|
43,
|
||||||
|
32,
|
||||||
|
112,
|
||||||
|
209,
|
||||||
|
173,
|
||||||
|
96,
|
||||||
|
143,
|
||||||
|
43,
|
||||||
|
220,
|
||||||
|
140,
|
||||||
|
26,
|
||||||
|
205,
|
||||||
|
34,
|
||||||
|
34,
|
||||||
|
53,
|
||||||
|
157,
|
||||||
|
41,
|
||||||
|
167,
|
||||||
|
125,
|
||||||
|
235,
|
||||||
|
243,
|
||||||
|
85,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
93,
|
||||||
|
109,
|
||||||
|
233,
|
||||||
|
186
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix6.json
vendored
Normal file
212
test/fixtures/fix6.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68,
|
||||||
|
68
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
198,
|
||||||
|
59,
|
||||||
|
91,
|
||||||
|
107,
|
||||||
|
222,
|
||||||
|
214,
|
||||||
|
31,
|
||||||
|
230,
|
||||||
|
112,
|
||||||
|
1,
|
||||||
|
199,
|
||||||
|
174,
|
||||||
|
17,
|
||||||
|
224,
|
||||||
|
194,
|
||||||
|
225,
|
||||||
|
138,
|
||||||
|
65,
|
||||||
|
58,
|
||||||
|
160,
|
||||||
|
31,
|
||||||
|
249,
|
||||||
|
102,
|
||||||
|
16,
|
||||||
|
74,
|
||||||
|
46,
|
||||||
|
85,
|
||||||
|
30,
|
||||||
|
232,
|
||||||
|
249,
|
||||||
|
120,
|
||||||
|
108,
|
||||||
|
38,
|
||||||
|
165,
|
||||||
|
105,
|
||||||
|
27,
|
||||||
|
12,
|
||||||
|
98,
|
||||||
|
98,
|
||||||
|
108,
|
||||||
|
130,
|
||||||
|
163,
|
||||||
|
16,
|
||||||
|
137,
|
||||||
|
116,
|
||||||
|
104,
|
||||||
|
153,
|
||||||
|
188,
|
||||||
|
5,
|
||||||
|
251,
|
||||||
|
163,
|
||||||
|
244,
|
||||||
|
0,
|
||||||
|
58,
|
||||||
|
1,
|
||||||
|
207,
|
||||||
|
25,
|
||||||
|
78,
|
||||||
|
188,
|
||||||
|
210,
|
||||||
|
205,
|
||||||
|
221,
|
||||||
|
48,
|
||||||
|
132,
|
||||||
|
72,
|
||||||
|
209,
|
||||||
|
11,
|
||||||
|
67,
|
||||||
|
14,
|
||||||
|
42,
|
||||||
|
218,
|
||||||
|
71,
|
||||||
|
148,
|
||||||
|
252,
|
||||||
|
126,
|
||||||
|
183,
|
||||||
|
60,
|
||||||
|
32,
|
||||||
|
93,
|
||||||
|
36,
|
||||||
|
125,
|
||||||
|
103,
|
||||||
|
191,
|
||||||
|
117,
|
||||||
|
82,
|
||||||
|
241,
|
||||||
|
190,
|
||||||
|
176,
|
||||||
|
1,
|
||||||
|
129,
|
||||||
|
118,
|
||||||
|
112,
|
||||||
|
139,
|
||||||
|
153,
|
||||||
|
178,
|
||||||
|
56,
|
||||||
|
61,
|
||||||
|
91,
|
||||||
|
52,
|
||||||
|
198
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix7.json
vendored
Normal file
212
test/fixtures/fix7.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
206,
|
||||||
|
241,
|
||||||
|
99,
|
||||||
|
120,
|
||||||
|
248,
|
||||||
|
163,
|
||||||
|
57,
|
||||||
|
30,
|
||||||
|
216,
|
||||||
|
86,
|
||||||
|
255,
|
||||||
|
192,
|
||||||
|
89,
|
||||||
|
193,
|
||||||
|
176,
|
||||||
|
17,
|
||||||
|
78,
|
||||||
|
62,
|
||||||
|
80,
|
||||||
|
149,
|
||||||
|
189,
|
||||||
|
235,
|
||||||
|
27,
|
||||||
|
157,
|
||||||
|
175,
|
||||||
|
248,
|
||||||
|
7,
|
||||||
|
19,
|
||||||
|
222,
|
||||||
|
64,
|
||||||
|
111,
|
||||||
|
199,
|
||||||
|
204,
|
||||||
|
163,
|
||||||
|
26,
|
||||||
|
16,
|
||||||
|
95,
|
||||||
|
221,
|
||||||
|
70,
|
||||||
|
32,
|
||||||
|
239,
|
||||||
|
4,
|
||||||
|
58,
|
||||||
|
162,
|
||||||
|
253,
|
||||||
|
237,
|
||||||
|
8,
|
||||||
|
51,
|
||||||
|
94,
|
||||||
|
3,
|
||||||
|
165,
|
||||||
|
186,
|
||||||
|
223,
|
||||||
|
210,
|
||||||
|
116,
|
||||||
|
101,
|
||||||
|
228,
|
||||||
|
82,
|
||||||
|
103,
|
||||||
|
76,
|
||||||
|
74,
|
||||||
|
44,
|
||||||
|
51,
|
||||||
|
117,
|
||||||
|
189,
|
||||||
|
140,
|
||||||
|
132,
|
||||||
|
230,
|
||||||
|
188,
|
||||||
|
243,
|
||||||
|
24,
|
||||||
|
158,
|
||||||
|
149,
|
||||||
|
93,
|
||||||
|
147,
|
||||||
|
226,
|
||||||
|
113,
|
||||||
|
195,
|
||||||
|
31,
|
||||||
|
24,
|
||||||
|
9,
|
||||||
|
19,
|
||||||
|
27,
|
||||||
|
132,
|
||||||
|
180,
|
||||||
|
152,
|
||||||
|
26,
|
||||||
|
65,
|
||||||
|
125,
|
||||||
|
144,
|
||||||
|
86,
|
||||||
|
167,
|
||||||
|
41,
|
||||||
|
144,
|
||||||
|
158,
|
||||||
|
204,
|
||||||
|
76,
|
||||||
|
46,
|
||||||
|
181,
|
||||||
|
110
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix8.json
vendored
Normal file
212
test/fixtures/fix8.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75,
|
||||||
|
75
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
153,
|
||||||
|
161,
|
||||||
|
201,
|
||||||
|
66,
|
||||||
|
87,
|
||||||
|
46,
|
||||||
|
242,
|
||||||
|
87,
|
||||||
|
136,
|
||||||
|
238,
|
||||||
|
151,
|
||||||
|
198,
|
||||||
|
129,
|
||||||
|
122,
|
||||||
|
62,
|
||||||
|
205,
|
||||||
|
142,
|
||||||
|
252,
|
||||||
|
109,
|
||||||
|
187,
|
||||||
|
238,
|
||||||
|
183,
|
||||||
|
63,
|
||||||
|
95,
|
||||||
|
240,
|
||||||
|
97,
|
||||||
|
220,
|
||||||
|
209,
|
||||||
|
37,
|
||||||
|
144,
|
||||||
|
237,
|
||||||
|
84,
|
||||||
|
251,
|
||||||
|
149,
|
||||||
|
152,
|
||||||
|
222,
|
||||||
|
89,
|
||||||
|
200,
|
||||||
|
208,
|
||||||
|
119,
|
||||||
|
213,
|
||||||
|
38,
|
||||||
|
65,
|
||||||
|
19,
|
||||||
|
2,
|
||||||
|
252,
|
||||||
|
193,
|
||||||
|
125,
|
||||||
|
94,
|
||||||
|
76,
|
||||||
|
182,
|
||||||
|
198,
|
||||||
|
243,
|
||||||
|
121,
|
||||||
|
253,
|
||||||
|
16,
|
||||||
|
45,
|
||||||
|
254,
|
||||||
|
82,
|
||||||
|
47,
|
||||||
|
146,
|
||||||
|
206,
|
||||||
|
41,
|
||||||
|
105,
|
||||||
|
254,
|
||||||
|
237,
|
||||||
|
236,
|
||||||
|
141,
|
||||||
|
118,
|
||||||
|
214,
|
||||||
|
197,
|
||||||
|
228,
|
||||||
|
59,
|
||||||
|
125,
|
||||||
|
45,
|
||||||
|
200,
|
||||||
|
61,
|
||||||
|
24,
|
||||||
|
110,
|
||||||
|
26,
|
||||||
|
235,
|
||||||
|
92,
|
||||||
|
175,
|
||||||
|
255,
|
||||||
|
85,
|
||||||
|
119,
|
||||||
|
57,
|
||||||
|
160,
|
||||||
|
145,
|
||||||
|
107,
|
||||||
|
206,
|
||||||
|
28,
|
||||||
|
62,
|
||||||
|
10,
|
||||||
|
166,
|
||||||
|
89,
|
||||||
|
7,
|
||||||
|
20,
|
||||||
|
246,
|
||||||
|
243
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
212
test/fixtures/fix9.json
vendored
Normal file
212
test/fixtures/fix9.json
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
35
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "Buffer",
|
||||||
|
"data": [
|
||||||
|
79,
|
||||||
|
215,
|
||||||
|
22,
|
||||||
|
29,
|
||||||
|
132,
|
||||||
|
130,
|
||||||
|
214,
|
||||||
|
248,
|
||||||
|
237,
|
||||||
|
124,
|
||||||
|
234,
|
||||||
|
54,
|
||||||
|
215,
|
||||||
|
78,
|
||||||
|
0,
|
||||||
|
211,
|
||||||
|
246,
|
||||||
|
222,
|
||||||
|
54,
|
||||||
|
91,
|
||||||
|
53,
|
||||||
|
2,
|
||||||
|
49,
|
||||||
|
40,
|
||||||
|
0,
|
||||||
|
202,
|
||||||
|
188,
|
||||||
|
25,
|
||||||
|
184,
|
||||||
|
121,
|
||||||
|
164,
|
||||||
|
235,
|
||||||
|
189,
|
||||||
|
97,
|
||||||
|
14,
|
||||||
|
0,
|
||||||
|
83,
|
||||||
|
166,
|
||||||
|
88,
|
||||||
|
62,
|
||||||
|
55,
|
||||||
|
49,
|
||||||
|
79,
|
||||||
|
153,
|
||||||
|
136,
|
||||||
|
193,
|
||||||
|
133,
|
||||||
|
206,
|
||||||
|
172,
|
||||||
|
99,
|
||||||
|
207,
|
||||||
|
73,
|
||||||
|
246,
|
||||||
|
216,
|
||||||
|
192,
|
||||||
|
107,
|
||||||
|
50,
|
||||||
|
206,
|
||||||
|
167,
|
||||||
|
242,
|
||||||
|
25,
|
||||||
|
180,
|
||||||
|
63,
|
||||||
|
184,
|
||||||
|
201,
|
||||||
|
61,
|
||||||
|
90,
|
||||||
|
242,
|
||||||
|
223,
|
||||||
|
192,
|
||||||
|
13,
|
||||||
|
140,
|
||||||
|
31,
|
||||||
|
240,
|
||||||
|
112,
|
||||||
|
157,
|
||||||
|
250,
|
||||||
|
90,
|
||||||
|
142,
|
||||||
|
3,
|
||||||
|
40,
|
||||||
|
12,
|
||||||
|
106,
|
||||||
|
63,
|
||||||
|
73,
|
||||||
|
42,
|
||||||
|
79,
|
||||||
|
82,
|
||||||
|
20,
|
||||||
|
41,
|
||||||
|
187,
|
||||||
|
173,
|
||||||
|
23,
|
||||||
|
85,
|
||||||
|
59,
|
||||||
|
253,
|
||||||
|
212,
|
||||||
|
191,
|
||||||
|
109,
|
||||||
|
46
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
20
test/fixtures/go-aes.js
vendored
Normal file
20
test/fixtures/go-aes.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
16: {
|
||||||
|
inputs: [
|
||||||
|
[47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47],
|
||||||
|
[24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24],
|
||||||
|
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
|
||||||
|
[25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25],
|
||||||
|
[48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48]
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
[121, 104, 0, 151, 57, 137, 22, 239, 234, 151, 58, 15, 100, 22, 228, 110, 85, 248, 249, 15, 145, 128, 223, 25, 192, 175, 132, 169, 98, 203, 231, 106, 224, 102, 206, 244, 29, 213, 36, 2, 26, 213, 94, 29, 134, 219, 136, 73, 212, 176, 33, 95, 198, 91, 148, 139, 132, 252, 182, 115, 116, 160, 146, 194, 0, 97, 181, 0, 193, 149, 21, 51, 248, 97, 32, 62, 86, 153, 238, 67, 38, 34, 55, 143, 70, 193, 99, 107, 31, 67, 90, 97, 55, 63, 69, 203, 33, 233, 74, 237],
|
||||||
|
[109, 172, 127, 179, 110, 222, 79, 219, 87, 76, 70, 204, 166, 110, 184, 229, 90, 49, 160, 252, 78, 58, 73, 51, 152, 218, 3, 200, 10, 124, 152, 117, 137, 40, 23, 127, 56, 57, 203, 31, 101, 227, 31, 198, 223, 86, 98, 120, 100, 86, 116, 144, 142, 127, 68, 175, 249, 232, 22, 83, 22, 68, 60, 230, 146, 22, 153, 193, 67, 5, 51, 253, 239, 210, 80, 31, 254, 103, 185, 145, 123, 99, 205, 175, 156, 144, 191, 67, 31, 236, 43, 98, 197, 235, 31, 50, 69, 228, 100, 64],
|
||||||
|
[191, 93, 126, 191, 180, 42, 118, 144, 28, 188, 211, 191, 211, 130, 170, 153, 134, 240, 179, 83, 75, 23, 42, 68, 158, 200, 123, 155, 57, 169, 152, 133, 33, 114, 90, 29, 131, 91, 70, 105, 83, 45, 40, 47, 77, 96, 97, 8, 40, 1, 110, 245, 106, 172, 152, 146, 5, 114, 132, 0, 179, 31, 44, 78, 19, 109, 92, 199, 226, 36, 12, 74, 180, 241, 224, 107, 83, 13, 167, 27, 251, 101, 193, 98, 49, 90, 225, 197, 75, 213, 144, 52, 235, 130, 92, 247, 219, 139, 209, 132],
|
||||||
|
[191, 110, 53, 190, 250, 44, 190, 136, 22, 209, 131, 200, 112, 31, 61, 183, 247, 95, 4, 249, 69, 147, 238, 74, 18, 71, 197, 115, 141, 226, 102, 92, 91, 128, 181, 172, 67, 109, 17, 165, 52, 10, 55, 31, 55, 225, 253, 140, 154, 35, 104, 62, 119, 103, 197, 152, 125, 134, 140, 181, 170, 76, 75, 114, 195, 188, 68, 197, 28, 47, 116, 82, 34, 128, 232, 122, 14, 229, 122, 161, 36, 212, 161, 164, 145, 86, 215, 233, 222, 50, 143, 89, 131, 32, 130, 196, 109, 36, 204, 254],
|
||||||
|
[97, 142, 8, 37, 69, 173, 124, 180, 97, 70, 45, 91, 196, 126, 184, 135, 213, 104, 171, 89, 231, 63, 43, 42, 7, 245, 75, 165, 205, 182, 24, 50, 170, 217, 128, 112, 114, 215, 209, 145, 135, 235, 179, 212, 5, 81, 142, 199, 53, 221, 39, 239, 167, 21, 237, 168, 145, 249, 250, 108, 2, 247, 89, 73, 228, 227, 255, 155, 121, 157, 205, 96, 43, 32, 112, 209, 173, 96, 143, 43, 220, 140, 26, 205, 34, 34, 53, 157, 41, 167, 125, 235, 243, 85, 13, 14, 93, 109, 233, 186]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
6
test/fixtures/go-elliptic-key.js
vendored
6
test/fixtures/go-elliptic-key.js
vendored
@@ -3,10 +3,10 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
curve: 'P-256',
|
curve: 'P-256',
|
||||||
bob: {
|
bob: {
|
||||||
private: [
|
private: Uint8Array.from([
|
||||||
181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170
|
181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170
|
||||||
],
|
]),
|
||||||
public: new Buffer([
|
public: Uint8Array.from([
|
||||||
4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90
|
4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
42
test/fixtures/go-key-ed25519.js
vendored
Normal file
42
test/fixtures/go-key-ed25519.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Generation code from https://github.com/libp2p/js-libp2p-crypto/issues/175#issuecomment-634467463
|
||||||
|
//
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "crypto/rand"
|
||||||
|
// "fmt"
|
||||||
|
// "strings"
|
||||||
|
|
||||||
|
// "github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// func main() {
|
||||||
|
// priv, pub, _ := crypto.GenerateEd25519Key(rand.Reader)
|
||||||
|
// pubkeyBytes, _ := pub.Bytes()
|
||||||
|
// privkeyBytes, _ := priv.Bytes()
|
||||||
|
// data := []byte("hello! and welcome to some awesome crypto primitives")
|
||||||
|
// sig, _ := priv.Sign(data)
|
||||||
|
// fmt.Println("{\n publicKey: Uint8Array.from(", strings.Replace(fmt.Sprint(pubkeyBytes), " ", ",", -1), "),")
|
||||||
|
// fmt.Println(" privateKey: Uint8Array.from(", strings.Replace(fmt.Sprint(privkeyBytes), " ", ",", -1), "),")
|
||||||
|
// fmt.Println(" data: Uint8Array.from(", strings.Replace(fmt.Sprint(data), " ", ",", -1), "),")
|
||||||
|
// fmt.Println(" signature: Uint8Array.from(", strings.Replace(fmt.Sprint(sig), " ", ",", -1), ")\n}")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
// The legacy key unnecessarily appends the publickey. (It's already included) See https://github.com/libp2p/js-libp2p-crypto/issues/175
|
||||||
|
redundantPubKey: {
|
||||||
|
privateKey: Uint8Array.from([8, 1, 18, 96, 201, 208, 1, 110, 176, 16, 230, 37, 66, 184, 149, 252, 78, 56, 206, 136, 2, 38, 118, 152, 226, 197, 117, 200, 54, 189, 156, 218, 184, 7, 118, 57, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37]),
|
||||||
|
publicKey: Uint8Array.from([8, 1, 18, 32, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37]),
|
||||||
|
data: Uint8Array.from([104, 101, 108, 108, 111, 33, 32, 97, 110, 100, 32, 119, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 115, 111, 109, 101, 32, 97, 119, 101, 115, 111, 109, 101, 32, 99, 114, 121, 112, 116, 111, 32, 112, 114, 105, 109, 105, 116, 105, 118, 101, 115]),
|
||||||
|
signature: Uint8Array.from([7, 230, 175, 164, 228, 58, 78, 208, 62, 243, 73, 142, 83, 195, 176, 217, 166, 62, 41, 165, 168, 164, 75, 179, 163, 86, 102, 32, 18, 84, 150, 237, 39, 207, 213, 20, 134, 237, 50, 41, 176, 183, 229, 133, 38, 255, 42, 228, 68, 186, 100, 14, 175, 156, 243, 118, 125, 125, 120, 212, 124, 103, 252, 12])
|
||||||
|
},
|
||||||
|
verify: {
|
||||||
|
publicKey: Uint8Array.from([8, 1, 18, 32, 163, 176, 195, 47, 254, 208, 49, 5, 192, 102, 32, 63, 58, 202, 171, 153, 146, 164, 25, 212, 25, 91, 146, 26, 117, 165, 148, 6, 207, 90, 217, 126]),
|
||||||
|
privateKey: Uint8Array.from([8, 1, 18, 64, 232, 56, 175, 20, 240, 160, 19, 47, 92, 88, 115, 221, 164, 13, 36, 162, 158, 136, 247, 31, 29, 231, 76, 143, 12, 91, 193, 4, 88, 33, 67, 23, 163, 176, 195, 47, 254, 208, 49, 5, 192, 102, 32, 63, 58, 202, 171, 153, 146, 164, 25, 212, 25, 91, 146, 26, 117, 165, 148, 6, 207, 90, 217, 126]),
|
||||||
|
data: Uint8Array.from([104, 101, 108, 108, 111, 33, 32, 97, 110, 100, 32, 119, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 115, 111, 109, 101, 32, 97, 119, 101, 115, 111, 109, 101, 32, 99, 114, 121, 112, 116, 111, 32, 112, 114, 105, 109, 105, 116, 105, 118, 101, 115]),
|
||||||
|
signature: Uint8Array.from([160, 125, 30, 62, 213, 189, 239, 92, 87, 76, 205, 169, 251, 149, 187, 57, 96, 85, 175, 213, 22, 132, 229, 60, 196, 18, 117, 194, 12, 174, 135, 31, 39, 168, 174, 103, 78, 55, 37, 222, 37, 172, 222, 239, 153, 63, 197, 152, 67, 167, 191, 215, 161, 212, 216, 163, 81, 77, 45, 228, 151, 79, 101, 1])
|
||||||
|
}
|
||||||
|
}
|
14
test/fixtures/go-key-rsa.js
vendored
14
test/fixtures/go-key-rsa.js
vendored
@@ -2,29 +2,29 @@
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
private: {
|
private: {
|
||||||
hash: new Buffer([
|
hash: Uint8Array.from([
|
||||||
18, 32, 168, 125, 165, 65, 34, 157, 209, 4, 24, 158, 80, 196, 125, 86, 103, 0, 228, 145, 109, 252, 153, 7, 189, 9, 16, 37, 239, 36, 48, 78, 214, 212
|
18, 32, 168, 125, 165, 65, 34, 157, 209, 4, 24, 158, 80, 196, 125, 86, 103, 0, 228, 145, 109, 252, 153, 7, 189, 9, 16, 37, 239, 36, 48, 78, 214, 212
|
||||||
]),
|
]),
|
||||||
key: new Buffer([
|
key: Uint8Array.from([
|
||||||
8, 0, 18, 192, 2, 48, 130, 1, 60, 2, 1, 0, 2, 65, 0, 230, 157, 160, 242, 74, 222, 87, 0, 77, 180, 91, 175, 217, 166, 2, 95, 193, 239, 195, 140, 224, 57, 84, 207, 46, 172, 113, 196, 20, 133, 117, 205, 45, 7, 224, 41, 40, 195, 254, 124, 14, 84, 223, 147, 67, 198, 48, 36, 53, 161, 112, 46, 153, 90, 19, 123, 94, 247, 5, 116, 1, 238, 32, 15, 2, 3, 1, 0, 1, 2, 65, 0, 191, 59, 140, 255, 254, 23, 123, 91, 148, 19, 240, 71, 213, 26, 181, 51, 68, 181, 150, 153, 214, 65, 148, 83, 45, 103, 239, 250, 225, 237, 125, 173, 111, 244, 37, 124, 87, 178, 86, 10, 14, 207, 63, 105, 213, 37, 81, 23, 230, 4, 222, 179, 144, 40, 252, 163, 190, 7, 241, 221, 28, 54, 225, 209, 2, 33, 0, 235, 132, 229, 150, 99, 182, 176, 194, 198, 65, 210, 160, 184, 70, 82, 49, 235, 199, 14, 11, 92, 66, 237, 45, 220, 72, 235, 1, 244, 145, 205, 57, 2, 33, 0, 250, 171, 146, 180, 188, 194, 14, 152, 52, 64, 38, 52, 158, 86, 46, 109, 66, 100, 122, 43, 88, 167, 143, 98, 104, 143, 160, 60, 171, 185, 31, 135, 2, 33, 0, 206, 47, 255, 203, 100, 170, 137, 31, 75, 240, 78, 84, 212, 95, 4, 16, 158, 73, 27, 27, 136, 255, 50, 163, 166, 169, 211, 204, 87, 111, 217, 201, 2, 33, 0, 177, 51, 194, 213, 3, 175, 7, 84, 47, 115, 189, 206, 106, 180, 47, 195, 203, 48, 110, 112, 224, 14, 43, 189, 124, 127, 51, 222, 79, 226, 225, 87, 2, 32, 67, 23, 190, 222, 106, 22, 115, 139, 217, 244, 178, 53, 153, 99, 5, 176, 72, 77, 193, 61, 67, 134, 37, 238, 69, 66, 159, 28, 39, 5, 238, 125
|
8, 0, 18, 192, 2, 48, 130, 1, 60, 2, 1, 0, 2, 65, 0, 230, 157, 160, 242, 74, 222, 87, 0, 77, 180, 91, 175, 217, 166, 2, 95, 193, 239, 195, 140, 224, 57, 84, 207, 46, 172, 113, 196, 20, 133, 117, 205, 45, 7, 224, 41, 40, 195, 254, 124, 14, 84, 223, 147, 67, 198, 48, 36, 53, 161, 112, 46, 153, 90, 19, 123, 94, 247, 5, 116, 1, 238, 32, 15, 2, 3, 1, 0, 1, 2, 65, 0, 191, 59, 140, 255, 254, 23, 123, 91, 148, 19, 240, 71, 213, 26, 181, 51, 68, 181, 150, 153, 214, 65, 148, 83, 45, 103, 239, 250, 225, 237, 125, 173, 111, 244, 37, 124, 87, 178, 86, 10, 14, 207, 63, 105, 213, 37, 81, 23, 230, 4, 222, 179, 144, 40, 252, 163, 190, 7, 241, 221, 28, 54, 225, 209, 2, 33, 0, 235, 132, 229, 150, 99, 182, 176, 194, 198, 65, 210, 160, 184, 70, 82, 49, 235, 199, 14, 11, 92, 66, 237, 45, 220, 72, 235, 1, 244, 145, 205, 57, 2, 33, 0, 250, 171, 146, 180, 188, 194, 14, 152, 52, 64, 38, 52, 158, 86, 46, 109, 66, 100, 122, 43, 88, 167, 143, 98, 104, 143, 160, 60, 171, 185, 31, 135, 2, 33, 0, 206, 47, 255, 203, 100, 170, 137, 31, 75, 240, 78, 84, 212, 95, 4, 16, 158, 73, 27, 27, 136, 255, 50, 163, 166, 169, 211, 204, 87, 111, 217, 201, 2, 33, 0, 177, 51, 194, 213, 3, 175, 7, 84, 47, 115, 189, 206, 106, 180, 47, 195, 203, 48, 110, 112, 224, 14, 43, 189, 124, 127, 51, 222, 79, 226, 225, 87, 2, 32, 67, 23, 190, 222, 106, 22, 115, 139, 217, 244, 178, 53, 153, 99, 5, 176, 72, 77, 193, 61, 67, 134, 37, 238, 69, 66, 159, 28, 39, 5, 238, 125
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
public: {
|
public: {
|
||||||
hash: new Buffer([
|
hash: Uint8Array.from([
|
||||||
18, 32, 112, 151, 163, 167, 204, 243, 175, 123, 208, 162, 90, 84, 199, 174, 202, 110, 0, 119, 27, 202, 7, 149, 161, 251, 215, 168, 163, 54, 93, 54, 195, 20
|
18, 32, 112, 151, 163, 167, 204, 243, 175, 123, 208, 162, 90, 84, 199, 174, 202, 110, 0, 119, 27, 202, 7, 149, 161, 251, 215, 168, 163, 54, 93, 54, 195, 20
|
||||||
]),
|
]),
|
||||||
key: new Buffer([
|
key: Uint8Array.from([
|
||||||
8, 0, 18, 94, 48, 92, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 75, 0, 48, 72, 2, 65, 0, 230, 157, 160, 242, 74, 222, 87, 0, 77, 180, 91, 175, 217, 166, 2, 95, 193, 239, 195, 140, 224, 57, 84, 207, 46, 172, 113, 196, 20, 133, 117, 205, 45, 7, 224, 41, 40, 195, 254, 124, 14, 84, 223, 147, 67, 198, 48, 36, 53, 161, 112, 46, 153, 90, 19, 123, 94, 247, 5, 116, 1, 238, 32, 15, 2, 3, 1, 0, 1
|
8, 0, 18, 94, 48, 92, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 75, 0, 48, 72, 2, 65, 0, 230, 157, 160, 242, 74, 222, 87, 0, 77, 180, 91, 175, 217, 166, 2, 95, 193, 239, 195, 140, 224, 57, 84, 207, 46, 172, 113, 196, 20, 133, 117, 205, 45, 7, 224, 41, 40, 195, 254, 124, 14, 84, 223, 147, 67, 198, 48, 36, 53, 161, 112, 46, 153, 90, 19, 123, 94, 247, 5, 116, 1, 238, 32, 15, 2, 3, 1, 0, 1
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
verify: {
|
verify: {
|
||||||
signature: new Buffer([
|
signature: Uint8Array.from([
|
||||||
3, 116, 81, 57, 91, 194, 7, 1, 230, 236, 229, 142, 36, 209, 208, 107, 47, 52, 164, 236, 139, 35, 155, 97, 43, 64, 145, 91, 19, 218, 149, 63, 99, 164, 191, 110, 145, 37, 18, 7, 98, 112, 144, 35, 29, 186, 169, 150, 165, 88, 145, 170, 197, 110, 42, 163, 188, 10, 42, 63, 34, 93, 91, 94, 199, 110, 10, 82, 238, 80, 93, 93, 77, 130, 22, 216, 229, 172, 36, 229, 82, 162, 20, 78, 19, 46, 82, 243, 43, 80, 115, 125, 145, 231, 194, 224, 30, 187, 55, 228, 74, 52, 203, 191, 254, 148, 136, 218, 62, 147, 171, 130, 251, 181, 105, 29, 238, 207, 197, 249, 61, 105, 202, 172, 160, 174, 43, 124, 115, 130, 169, 30, 76, 41, 52, 200, 2, 26, 53, 190, 43, 20, 203, 10, 217, 250, 47, 102, 92, 103, 197, 22, 108, 184, 74, 218, 82, 202, 180, 98, 13, 114, 12, 92, 1, 139, 150, 170, 8, 92, 32, 116, 168, 219, 157, 162, 28, 77, 29, 29, 74, 136, 144, 49, 173, 245, 253, 76, 167, 200, 169, 163, 7, 49, 133, 120, 99, 191, 53, 10, 66, 26, 234, 240, 139, 235, 134, 30, 55, 248, 150, 100, 242, 150, 159, 198, 44, 78, 150, 7, 133, 139, 59, 76, 3, 225, 94, 13, 89, 122, 34, 95, 95, 107, 74, 169, 171, 169, 222, 25, 191, 182, 148, 116, 66, 67, 102, 12, 193, 217, 247, 243, 148, 233, 161, 157
|
3, 116, 81, 57, 91, 194, 7, 1, 230, 236, 229, 142, 36, 209, 208, 107, 47, 52, 164, 236, 139, 35, 155, 97, 43, 64, 145, 91, 19, 218, 149, 63, 99, 164, 191, 110, 145, 37, 18, 7, 98, 112, 144, 35, 29, 186, 169, 150, 165, 88, 145, 170, 197, 110, 42, 163, 188, 10, 42, 63, 34, 93, 91, 94, 199, 110, 10, 82, 238, 80, 93, 93, 77, 130, 22, 216, 229, 172, 36, 229, 82, 162, 20, 78, 19, 46, 82, 243, 43, 80, 115, 125, 145, 231, 194, 224, 30, 187, 55, 228, 74, 52, 203, 191, 254, 148, 136, 218, 62, 147, 171, 130, 251, 181, 105, 29, 238, 207, 197, 249, 61, 105, 202, 172, 160, 174, 43, 124, 115, 130, 169, 30, 76, 41, 52, 200, 2, 26, 53, 190, 43, 20, 203, 10, 217, 250, 47, 102, 92, 103, 197, 22, 108, 184, 74, 218, 82, 202, 180, 98, 13, 114, 12, 92, 1, 139, 150, 170, 8, 92, 32, 116, 168, 219, 157, 162, 28, 77, 29, 29, 74, 136, 144, 49, 173, 245, 253, 76, 167, 200, 169, 163, 7, 49, 133, 120, 99, 191, 53, 10, 66, 26, 234, 240, 139, 235, 134, 30, 55, 248, 150, 100, 242, 150, 159, 198, 44, 78, 150, 7, 133, 139, 59, 76, 3, 225, 94, 13, 89, 122, 34, 95, 95, 107, 74, 169, 171, 169, 222, 25, 191, 182, 148, 116, 66, 67, 102, 12, 193, 217, 247, 243, 148, 233, 161, 157
|
||||||
]),
|
]),
|
||||||
data: new Buffer([
|
data: Uint8Array.from([
|
||||||
10, 16, 27, 128, 228, 220, 147, 176, 53, 105, 175, 171, 32, 213, 35, 236, 203, 60, 18, 171, 2, 8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 181, 113, 138, 108, 208, 103, 166, 102, 37, 36, 204, 250, 228, 165, 44, 64, 176, 210, 205, 141, 241, 55, 200, 110, 98, 68, 85, 199, 254, 19, 86, 204, 63, 250, 167, 38, 59, 249, 146, 228, 73, 171, 63, 18, 96, 104, 191, 137, 186, 244, 255, 90, 16, 119, 195, 52, 177, 213, 254, 187, 174, 84, 174, 173, 12, 236, 53, 234, 3, 209, 82, 37, 78, 111, 214, 135, 76, 195, 9, 242, 134, 188, 153, 84, 139, 231, 51, 146, 177, 60, 12, 25, 158, 91, 215, 152, 7, 0, 84, 35, 36, 230, 227, 67, 198, 72, 50, 110, 37, 209, 98, 193, 65, 93, 173, 199, 4, 198, 102, 99, 148, 144, 224, 217, 114, 53, 144, 245, 251, 114, 211, 20, 82, 163, 123, 75, 16, 192, 106, 213, 128, 2, 11, 200, 203, 84, 41, 199, 224, 155, 171, 217, 64, 109, 116, 188, 151, 183, 173, 52, 205, 164, 93, 13, 251, 65, 182, 160, 154, 185, 239, 33, 184, 84, 159, 105, 101, 173, 194, 251, 123, 84, 92, 66, 61, 180, 45, 104, 162, 224, 214, 233, 64, 220, 165, 2, 104, 116, 150, 2, 234, 203, 112, 21, 124, 23, 48, 66, 30, 63, 30, 36, 246, 135, 203, 218, 115, 22, 189, 39, 39, 125, 205, 65, 222, 220, 77, 18, 84, 121, 161, 153, 125, 25, 139, 137, 170, 239, 150, 106, 119, 168, 216, 140, 113, 121, 26, 53, 118, 110, 53, 192, 244, 252, 145, 85, 2, 3, 1, 0, 1, 26, 17, 80, 45, 50, 53, 54, 44, 80, 45, 51, 56, 52, 44, 80, 45, 53, 50, 49, 34, 24, 65, 69, 83, 45, 50, 53, 54, 44, 65, 69, 83, 45, 49, 50, 56, 44, 66, 108, 111, 119, 102, 105, 115, 104, 42, 13, 83, 72, 65, 50, 53, 54, 44, 83, 72, 65, 53, 49, 50, 10, 16, 220, 83, 240, 105, 6, 203, 78, 83, 210, 115, 6, 106, 98, 82, 1, 161, 18, 171, 2, 8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 185, 234, 19, 191, 164, 33, 65, 94, 87, 42, 74, 83, 224, 25, 142, 44, 26, 7, 92, 242, 189, 42, 170, 197, 178, 92, 45, 240, 107, 141, 128, 59, 122, 252, 48, 140, 4, 85, 85, 203, 3, 197, 8, 127, 120, 98, 44, 169, 135, 196, 70, 137, 117, 180, 177, 134, 170, 35, 165, 88, 105, 30, 114, 138, 11, 96, 68, 99, 18, 149, 223, 166, 105, 12, 176, 77, 48, 214, 22, 236, 17, 154, 213, 209, 158, 169, 202, 5, 100, 210, 83, 90, 201, 38, 205, 246, 231, 106, 63, 86, 222, 143, 157, 173, 62, 4, 85, 232, 20, 188, 6, 209, 186, 132, 192, 117, 146, 181, 233, 26, 0, 240, 138, 206, 91, 170, 114, 137, 217, 132, 139, 242, 144, 213, 103, 101, 190, 146, 188, 250, 188, 134, 255, 70, 125, 78, 65, 136, 239, 190, 206, 139, 155, 140, 163, 233, 170, 247, 205, 87, 209, 19, 29, 173, 10, 147, 43, 28, 90, 46, 6, 197, 217, 186, 66, 68, 126, 76, 64, 184, 8, 170, 23, 79, 243, 223, 119, 133, 118, 50, 226, 44, 246, 176, 10, 161, 219, 83, 54, 68, 248, 5, 14, 177, 114, 54, 63, 11, 71, 136, 142, 56, 151, 123, 230, 61, 80, 15, 180, 42, 49, 220, 148, 99, 231, 20, 230, 220, 85, 207, 187, 37, 210, 137, 171, 125, 71, 14, 53, 100, 91, 83, 209, 50, 132, 165, 253, 25, 161, 5, 97, 164, 163, 83, 95, 53, 2, 3, 1, 0, 1, 26, 17, 80, 45, 50, 53, 54, 44, 80, 45, 51, 56, 52, 44, 80, 45, 53, 50, 49, 34, 15, 65, 69, 83, 45, 50, 53, 54, 44, 65, 69, 83, 45, 49, 50, 56, 42, 13, 83, 72, 65, 50, 53, 54, 44, 83, 72, 65, 53, 49, 50, 4, 97, 54, 203, 112, 136, 34, 231, 162, 19, 154, 131, 27, 105, 26, 121, 238, 120, 25, 203, 66, 232, 53, 198, 20, 19, 96, 119, 218, 90, 64, 170, 3, 132, 116, 1, 87, 116, 232, 165, 161, 198, 117, 167, 60, 145, 1, 253, 108, 50, 150, 117, 8, 140, 133, 48, 30, 236, 36, 84, 186, 22, 144, 87, 101
|
10, 16, 27, 128, 228, 220, 147, 176, 53, 105, 175, 171, 32, 213, 35, 236, 203, 60, 18, 171, 2, 8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 181, 113, 138, 108, 208, 103, 166, 102, 37, 36, 204, 250, 228, 165, 44, 64, 176, 210, 205, 141, 241, 55, 200, 110, 98, 68, 85, 199, 254, 19, 86, 204, 63, 250, 167, 38, 59, 249, 146, 228, 73, 171, 63, 18, 96, 104, 191, 137, 186, 244, 255, 90, 16, 119, 195, 52, 177, 213, 254, 187, 174, 84, 174, 173, 12, 236, 53, 234, 3, 209, 82, 37, 78, 111, 214, 135, 76, 195, 9, 242, 134, 188, 153, 84, 139, 231, 51, 146, 177, 60, 12, 25, 158, 91, 215, 152, 7, 0, 84, 35, 36, 230, 227, 67, 198, 72, 50, 110, 37, 209, 98, 193, 65, 93, 173, 199, 4, 198, 102, 99, 148, 144, 224, 217, 114, 53, 144, 245, 251, 114, 211, 20, 82, 163, 123, 75, 16, 192, 106, 213, 128, 2, 11, 200, 203, 84, 41, 199, 224, 155, 171, 217, 64, 109, 116, 188, 151, 183, 173, 52, 205, 164, 93, 13, 251, 65, 182, 160, 154, 185, 239, 33, 184, 84, 159, 105, 101, 173, 194, 251, 123, 84, 92, 66, 61, 180, 45, 104, 162, 224, 214, 233, 64, 220, 165, 2, 104, 116, 150, 2, 234, 203, 112, 21, 124, 23, 48, 66, 30, 63, 30, 36, 246, 135, 203, 218, 115, 22, 189, 39, 39, 125, 205, 65, 222, 220, 77, 18, 84, 121, 161, 153, 125, 25, 139, 137, 170, 239, 150, 106, 119, 168, 216, 140, 113, 121, 26, 53, 118, 110, 53, 192, 244, 252, 145, 85, 2, 3, 1, 0, 1, 26, 17, 80, 45, 50, 53, 54, 44, 80, 45, 51, 56, 52, 44, 80, 45, 53, 50, 49, 34, 24, 65, 69, 83, 45, 50, 53, 54, 44, 65, 69, 83, 45, 49, 50, 56, 44, 66, 108, 111, 119, 102, 105, 115, 104, 42, 13, 83, 72, 65, 50, 53, 54, 44, 83, 72, 65, 53, 49, 50, 10, 16, 220, 83, 240, 105, 6, 203, 78, 83, 210, 115, 6, 106, 98, 82, 1, 161, 18, 171, 2, 8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 185, 234, 19, 191, 164, 33, 65, 94, 87, 42, 74, 83, 224, 25, 142, 44, 26, 7, 92, 242, 189, 42, 170, 197, 178, 92, 45, 240, 107, 141, 128, 59, 122, 252, 48, 140, 4, 85, 85, 203, 3, 197, 8, 127, 120, 98, 44, 169, 135, 196, 70, 137, 117, 180, 177, 134, 170, 35, 165, 88, 105, 30, 114, 138, 11, 96, 68, 99, 18, 149, 223, 166, 105, 12, 176, 77, 48, 214, 22, 236, 17, 154, 213, 209, 158, 169, 202, 5, 100, 210, 83, 90, 201, 38, 205, 246, 231, 106, 63, 86, 222, 143, 157, 173, 62, 4, 85, 232, 20, 188, 6, 209, 186, 132, 192, 117, 146, 181, 233, 26, 0, 240, 138, 206, 91, 170, 114, 137, 217, 132, 139, 242, 144, 213, 103, 101, 190, 146, 188, 250, 188, 134, 255, 70, 125, 78, 65, 136, 239, 190, 206, 139, 155, 140, 163, 233, 170, 247, 205, 87, 209, 19, 29, 173, 10, 147, 43, 28, 90, 46, 6, 197, 217, 186, 66, 68, 126, 76, 64, 184, 8, 170, 23, 79, 243, 223, 119, 133, 118, 50, 226, 44, 246, 176, 10, 161, 219, 83, 54, 68, 248, 5, 14, 177, 114, 54, 63, 11, 71, 136, 142, 56, 151, 123, 230, 61, 80, 15, 180, 42, 49, 220, 148, 99, 231, 20, 230, 220, 85, 207, 187, 37, 210, 137, 171, 125, 71, 14, 53, 100, 91, 83, 209, 50, 132, 165, 253, 25, 161, 5, 97, 164, 163, 83, 95, 53, 2, 3, 1, 0, 1, 26, 17, 80, 45, 50, 53, 54, 44, 80, 45, 51, 56, 52, 44, 80, 45, 53, 50, 49, 34, 15, 65, 69, 83, 45, 50, 53, 54, 44, 65, 69, 83, 45, 49, 50, 56, 42, 13, 83, 72, 65, 50, 53, 54, 44, 83, 72, 65, 53, 49, 50, 4, 97, 54, 203, 112, 136, 34, 231, 162, 19, 154, 131, 27, 105, 26, 121, 238, 120, 25, 203, 66, 232, 53, 198, 20, 19, 96, 119, 218, 90, 64, 170, 3, 132, 116, 1, 87, 116, 232, 165, 161, 198, 117, 167, 60, 145, 1, 253, 108, 50, 150, 117, 8, 140, 133, 48, 30, 236, 36, 84, 186, 22, 144, 87, 101
|
||||||
]),
|
]),
|
||||||
publicKey: new Buffer([
|
publicKey: Uint8Array.from([
|
||||||
8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 181, 113, 138, 108, 208, 103, 166, 102, 37, 36, 204, 250, 228, 165, 44, 64, 176, 210, 205, 141, 241, 55, 200, 110, 98, 68, 85, 199, 254, 19, 86, 204, 63, 250, 167, 38, 59, 249, 146, 228, 73, 171, 63, 18, 96, 104, 191, 137, 186, 244, 255, 90, 16, 119, 195, 52, 177, 213, 254, 187, 174, 84, 174, 173, 12, 236, 53, 234, 3, 209, 82, 37, 78, 111, 214, 135, 76, 195, 9, 242, 134, 188, 153, 84, 139, 231, 51, 146, 177, 60, 12, 25, 158, 91, 215, 152, 7, 0, 84, 35, 36, 230, 227, 67, 198, 72, 50, 110, 37, 209, 98, 193, 65, 93, 173, 199, 4, 198, 102, 99, 148, 144, 224, 217, 114, 53, 144, 245, 251, 114, 211, 20, 82, 163, 123, 75, 16, 192, 106, 213, 128, 2, 11, 200, 203, 84, 41, 199, 224, 155, 171, 217, 64, 109, 116, 188, 151, 183, 173, 52, 205, 164, 93, 13, 251, 65, 182, 160, 154, 185, 239, 33, 184, 84, 159, 105, 101, 173, 194, 251, 123, 84, 92, 66, 61, 180, 45, 104, 162, 224, 214, 233, 64, 220, 165, 2, 104, 116, 150, 2, 234, 203, 112, 21, 124, 23, 48, 66, 30, 63, 30, 36, 246, 135, 203, 218, 115, 22, 189, 39, 39, 125, 205, 65, 222, 220, 77, 18, 84, 121, 161, 153, 125, 25, 139, 137, 170, 239, 150, 106, 119, 168, 216, 140, 113, 121, 26, 53, 118, 110, 53, 192, 244, 252, 145, 85, 2, 3, 1, 0, 1
|
8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 181, 113, 138, 108, 208, 103, 166, 102, 37, 36, 204, 250, 228, 165, 44, 64, 176, 210, 205, 141, 241, 55, 200, 110, 98, 68, 85, 199, 254, 19, 86, 204, 63, 250, 167, 38, 59, 249, 146, 228, 73, 171, 63, 18, 96, 104, 191, 137, 186, 244, 255, 90, 16, 119, 195, 52, 177, 213, 254, 187, 174, 84, 174, 173, 12, 236, 53, 234, 3, 209, 82, 37, 78, 111, 214, 135, 76, 195, 9, 242, 134, 188, 153, 84, 139, 231, 51, 146, 177, 60, 12, 25, 158, 91, 215, 152, 7, 0, 84, 35, 36, 230, 227, 67, 198, 72, 50, 110, 37, 209, 98, 193, 65, 93, 173, 199, 4, 198, 102, 99, 148, 144, 224, 217, 114, 53, 144, 245, 251, 114, 211, 20, 82, 163, 123, 75, 16, 192, 106, 213, 128, 2, 11, 200, 203, 84, 41, 199, 224, 155, 171, 217, 64, 109, 116, 188, 151, 183, 173, 52, 205, 164, 93, 13, 251, 65, 182, 160, 154, 185, 239, 33, 184, 84, 159, 105, 101, 173, 194, 251, 123, 84, 92, 66, 61, 180, 45, 104, 162, 224, 214, 233, 64, 220, 165, 2, 104, 116, 150, 2, 234, 203, 112, 21, 124, 23, 48, 66, 30, 63, 30, 36, 246, 135, 203, 218, 115, 22, 189, 39, 39, 125, 205, 65, 222, 220, 77, 18, 84, 121, 161, 153, 125, 25, 139, 137, 170, 239, 150, 106, 119, 168, 216, 140, 113, 121, 26, 53, 118, 110, 53, 192, 244, 252, 145, 85, 2, 3, 1, 0, 1
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
31
test/fixtures/go-key-secp256k1.js
vendored
Normal file
31
test/fixtures/go-key-secp256k1.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
// The keypair and signature below were generated in a gore repl session (https://github.com/motemen/gore)
|
||||||
|
// using the secp256k1 fork of go-libp2p-crypto by github user @vyzo
|
||||||
|
//
|
||||||
|
// gore> :import github.com/vyzo/go-libp2p-crypto
|
||||||
|
// gore> :import crypto/rand
|
||||||
|
// gore> :import io/ioutil
|
||||||
|
// gore> priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Secp256k1, 256, rand.Reader)
|
||||||
|
// gore> privBytes, err := priv.Bytes()
|
||||||
|
// gore> pubBytes, err := pub.Bytes()
|
||||||
|
// gore> msg := []byte("hello! and welcome to some awesome crypto primitives")
|
||||||
|
// gore> sig, err := priv.Sign(msg)
|
||||||
|
// gore> ioutil.WriteFile("/tmp/secp-go-priv.bin", privBytes, 0644)
|
||||||
|
// gore> ioutil.WriteFile("/tmp/secp-go-pub.bin", pubBytes, 0644)
|
||||||
|
// gore> ioutil.WriteFile("/tmp/secp-go-sig.bin", sig, 0644)
|
||||||
|
//
|
||||||
|
// The generated files were then read in a node repl with e.g.:
|
||||||
|
// > fs.readFileSync('/tmp/secp-go-pub.bin').toString('hex')
|
||||||
|
// '08021221029c0ce5d53646ed47112560297a3e59b78b8cbd4bae37c7a0c236eeb91d0fbeaf'
|
||||||
|
//
|
||||||
|
// and the results copy/pasted in here
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
privateKey: uint8ArrayFromString('08021220358f15db8c2014d570e8e3a622454e2273975a3cca443ec0c45375b13d381d18', 'base16'),
|
||||||
|
publicKey: uint8ArrayFromString('08021221029c0ce5d53646ed47112560297a3e59b78b8cbd4bae37c7a0c236eeb91d0fbeaf', 'base16'),
|
||||||
|
message: uint8ArrayFromString('hello! and welcome to some awesome crypto primitives'),
|
||||||
|
signature: uint8ArrayFromString('304402200e4c629e9f5d99439115e60989cd40087f6978c36078b0b50cf3d30af5c38d4102204110342c8e7f0809897c1c7a66e49e1c6b7cb0a6ed6993640ec2fe742c1899a9', 'base16')
|
||||||
|
}
|
14
test/fixtures/go-stretch-key.js
vendored
14
test/fixtures/go-stretch-key.js
vendored
@@ -3,28 +3,28 @@
|
|||||||
module.exports = [{
|
module.exports = [{
|
||||||
cipher: 'AES-256',
|
cipher: 'AES-256',
|
||||||
hash: 'SHA256',
|
hash: 'SHA256',
|
||||||
secret: new Buffer([
|
secret: Uint8Array.from([
|
||||||
195, 191, 209, 165, 209, 201, 127, 122, 136, 111, 31, 66, 111, 68, 38, 155, 216, 204, 46, 181, 200, 188, 170, 204, 104, 74, 239, 251, 173, 114, 222, 234
|
195, 191, 209, 165, 209, 201, 127, 122, 136, 111, 31, 66, 111, 68, 38, 155, 216, 204, 46, 181, 200, 188, 170, 204, 104, 74, 239, 251, 173, 114, 222, 234
|
||||||
]),
|
]),
|
||||||
k1: {
|
k1: {
|
||||||
iv: new Buffer([
|
iv: Uint8Array.from([
|
||||||
208, 132, 203, 169, 253, 52, 40, 83, 161, 91, 17, 71, 33, 136, 67, 96
|
208, 132, 203, 169, 253, 52, 40, 83, 161, 91, 17, 71, 33, 136, 67, 96
|
||||||
]),
|
]),
|
||||||
cipherKey: new Buffer([
|
cipherKey: Uint8Array.from([
|
||||||
156, 48, 241, 157, 92, 248, 153, 186, 114, 127, 195, 114, 106, 104, 215, 133, 35, 11, 131, 137, 123, 70, 74, 26, 15, 60, 189, 32, 67, 221, 115, 137
|
156, 48, 241, 157, 92, 248, 153, 186, 114, 127, 195, 114, 106, 104, 215, 133, 35, 11, 131, 137, 123, 70, 74, 26, 15, 60, 189, 32, 67, 221, 115, 137
|
||||||
]),
|
]),
|
||||||
macKey: new Buffer([
|
macKey: Uint8Array.from([
|
||||||
6, 179, 91, 245, 224, 56, 153, 120, 77, 140, 29, 5, 15, 213, 187, 65, 137, 230, 202, 120
|
6, 179, 91, 245, 224, 56, 153, 120, 77, 140, 29, 5, 15, 213, 187, 65, 137, 230, 202, 120
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
k2: {
|
k2: {
|
||||||
iv: new Buffer([
|
iv: Uint8Array.from([
|
||||||
236, 17, 34, 141, 90, 106, 197, 56, 197, 184, 157, 135, 91, 88, 112, 19
|
236, 17, 34, 141, 90, 106, 197, 56, 197, 184, 157, 135, 91, 88, 112, 19
|
||||||
]),
|
]),
|
||||||
cipherKey: new Buffer([
|
cipherKey: Uint8Array.from([
|
||||||
151, 145, 195, 219, 76, 195, 102, 109, 187, 231, 100, 150, 132, 245, 251, 130, 254, 37, 178, 55, 227, 34, 114, 39, 238, 34, 2, 193, 107, 130, 32, 87
|
151, 145, 195, 219, 76, 195, 102, 109, 187, 231, 100, 150, 132, 245, 251, 130, 254, 37, 178, 55, 227, 34, 114, 39, 238, 34, 2, 193, 107, 130, 32, 87
|
||||||
]),
|
]),
|
||||||
macKey: new Buffer([
|
macKey: Uint8Array.from([
|
||||||
3, 229, 77, 212, 241, 217, 23, 113, 220, 126, 38, 255, 18, 117, 108, 205, 198, 89, 1, 236
|
3, 229, 77, 212, 241, 217, 23, 113, 220, 126, 38, 255, 18, 117, 108, 205, 198, 89, 1, 236
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
10
test/fixtures/secp256k1.js
vendored
Normal file
10
test/fixtures/secp256k1.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// protobuf marshaled key pair generated with libp2p-crypto-secp256k1
|
||||||
|
// and marshaled with libp2p-crypto.marshalPublicKey / marshalPrivateKey
|
||||||
|
pbmPrivateKey: uint8ArrayFromString('08021220e0600103010000000100000000000000be1dc82c2e000000e8d6030301000000', 'base16'),
|
||||||
|
pbmPublicKey: uint8ArrayFromString('0802122103a9a7272a726fa083abf31ba44037f8347fbc5e5d3113d62a7c6bc26752fd8ee1', 'base16')
|
||||||
|
}
|
33
test/helpers/test-garbage-error-handling.js
Normal file
33
test/helpers/test-garbage-error-handling.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
const util = require('util')
|
||||||
|
const garbage = [uint8ArrayFromString('00010203040506070809', 'base16'), {}, null, false, undefined, true, 1, 0, uint8ArrayFromString(''), 'aGVsbG93b3JsZA==', 'helloworld', '']
|
||||||
|
|
||||||
|
function doTests (fncName, fnc, num, skipBuffersAndStrings) {
|
||||||
|
if (!num) {
|
||||||
|
num = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
garbage.forEach((garbage) => {
|
||||||
|
if (skipBuffersAndStrings && (garbage instanceof Uint8Array || (typeof garbage) === 'string')) {
|
||||||
|
// skip this garbage because it's a Uint8Array or a String and we were told do do that
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const args = []
|
||||||
|
for (let i = 0; i < num; i++) {
|
||||||
|
args.push(garbage)
|
||||||
|
}
|
||||||
|
it(fncName + '(' + args.map(garbage => util.inspect(garbage)).join(', ') + ')', async () => {
|
||||||
|
try {
|
||||||
|
await fnc.apply(null, args)
|
||||||
|
} catch (err) {
|
||||||
|
return // expected
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { doTests }
|
@@ -1,24 +0,0 @@
|
|||||||
/* eslint max-nested-callbacks: ["error", 8] */
|
|
||||||
/* eslint-env mocha */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect
|
|
||||||
const crypto = require('../src')
|
|
||||||
|
|
||||||
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
|
||||||
|
|
||||||
describe('HMAC', () => {
|
|
||||||
hashes.forEach((hash) => {
|
|
||||||
it(`${hash} - sign and verify`, (done) => {
|
|
||||||
crypto.hmac.create(hash, new Buffer('secret'), (err, hmac) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
|
|
||||||
hmac.digest(new Buffer('hello world'), (err, sig) => {
|
|
||||||
expect(err).to.not.exist
|
|
||||||
expect(sig).to.have.length(hmac.length)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
23
test/hmac/hmac.spec.js
Normal file
23
test/hmac/hmac.spec.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
const crypto = require('../../src')
|
||||||
|
|
||||||
|
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
||||||
|
|
||||||
|
describe('HMAC', () => {
|
||||||
|
hashes.forEach((hash) => {
|
||||||
|
it(`${hash} - sign and verify`, async () => {
|
||||||
|
const hmac = await crypto.hmac.create(hash, uint8ArrayFromString('secret'))
|
||||||
|
const sig = await hmac.digest(uint8ArrayFromString('hello world'))
|
||||||
|
expect(sig).to.have.length(hmac.length)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@@ -1,101 +0,0 @@
|
|||||||
/* eslint max-nested-callbacks: ["error", 8] */
|
|
||||||
/* eslint-env mocha */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect
|
|
||||||
|
|
||||||
const crypto = require('../src')
|
|
||||||
const fixtures = require('./fixtures/go-key-rsa')
|
|
||||||
|
|
||||||
describe('libp2p-crypto', () => {
|
|
||||||
let key
|
|
||||||
before((done) => {
|
|
||||||
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
key = _key
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('marshalPublicKey and unmarshalPublicKey', () => {
|
|
||||||
const key2 = crypto.unmarshalPublicKey(crypto.marshalPublicKey(key.public))
|
|
||||||
|
|
||||||
expect(key2.equals(key.public)).to.be.eql(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('marshalPrivateKey and unmarshalPrivateKey', (done) => {
|
|
||||||
crypto.unmarshalPrivateKey(crypto.marshalPrivateKey(key), (err, key2) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(key2.equals(key)).to.be.eql(true)
|
|
||||||
expect(key2.public.equals(key.public)).to.be.eql(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// marshalled keys seem to be slightly different
|
|
||||||
// unsure as to if this is just a difference in encoding
|
|
||||||
// or a bug
|
|
||||||
describe('go interop', () => {
|
|
||||||
it('unmarshals private key', (done) => {
|
|
||||||
crypto.unmarshalPrivateKey(fixtures.private.key, (err, key) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
const hash = fixtures.private.hash
|
|
||||||
expect(fixtures.private.key).to.be.eql(key.bytes)
|
|
||||||
|
|
||||||
key.hash((err, digest) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(digest).to.be.eql(hash)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('unmarshals public key', (done) => {
|
|
||||||
const key = crypto.unmarshalPublicKey(fixtures.public.key)
|
|
||||||
const hash = fixtures.public.hash
|
|
||||||
|
|
||||||
expect(crypto.marshalPublicKey(key)).to.be.eql(fixtures.public.key)
|
|
||||||
|
|
||||||
key.hash((err, digest) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(digest).to.be.eql(hash)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('unmarshal -> marshal, private key', (done) => {
|
|
||||||
crypto.unmarshalPrivateKey(fixtures.private.key, (err, key) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const marshalled = crypto.marshalPrivateKey(key)
|
|
||||||
expect(marshalled).to.be.eql(fixtures.private.key)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('unmarshal -> marshal, public key', () => {
|
|
||||||
const key = crypto.unmarshalPublicKey(fixtures.public.key)
|
|
||||||
const marshalled = crypto.marshalPublicKey(key)
|
|
||||||
expect(
|
|
||||||
fixtures.public.key.equals(marshalled)
|
|
||||||
).to.be.eql(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@@ -1,74 +0,0 @@
|
|||||||
/* eslint max-nested-callbacks: ["error", 8] */
|
|
||||||
/* eslint-env mocha */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect
|
|
||||||
|
|
||||||
const crypto = require('../src')
|
|
||||||
const fixtures = require('./fixtures/go-stretch-key')
|
|
||||||
|
|
||||||
describe('keyStretcher', () => {
|
|
||||||
describe('generate', () => {
|
|
||||||
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
|
|
||||||
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
|
||||||
let res
|
|
||||||
let secret
|
|
||||||
|
|
||||||
before((done) => {
|
|
||||||
crypto.generateEphemeralKeyPair('P-256', (err, _res) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
res = _res
|
|
||||||
res.genSharedKey(res.key, (err, _secret) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret = _secret
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ciphers.forEach((cipher) => {
|
|
||||||
hashes.forEach((hash) => {
|
|
||||||
it(`${cipher} - ${hash}`, (done) => {
|
|
||||||
crypto.keyStretcher(cipher, hash, secret, (err, keys) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(keys.k1).to.exist
|
|
||||||
expect(keys.k2).to.exist
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('go interop', () => {
|
|
||||||
fixtures.forEach((test) => {
|
|
||||||
it(`${test.cipher} - ${test.hash}`, (done) => {
|
|
||||||
const cipher = test.cipher
|
|
||||||
const hash = test.hash
|
|
||||||
const secret = test.secret
|
|
||||||
crypto.keyStretcher(cipher, hash, secret, (err, keys) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(keys.k1.iv).to.be.eql(test.k1.iv)
|
|
||||||
expect(keys.k1.cipherKey).to.be.eql(test.k1.cipherKey)
|
|
||||||
expect(keys.k1.macKey).to.be.eql(test.k1.macKey)
|
|
||||||
|
|
||||||
expect(keys.k2.iv).to.be.eql(test.k2.iv)
|
|
||||||
expect(keys.k2.cipherKey).to.be.eql(test.k2.cipherKey)
|
|
||||||
expect(keys.k2.macKey).to.be.eql(test.k2.macKey)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
185
test/keys/ed25519.spec.js
Normal file
185
test/keys/ed25519.spec.js
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
const crypto = require('../../src')
|
||||||
|
const ed25519 = crypto.keys.supportedKeys.ed25519
|
||||||
|
const fixtures = require('../fixtures/go-key-ed25519')
|
||||||
|
|
||||||
|
const testGarbage = require('../helpers/test-garbage-error-handling')
|
||||||
|
|
||||||
|
/** @typedef {import("libp2p-crypto").PrivateKey} PrivateKey */
|
||||||
|
|
||||||
|
describe('ed25519', function () {
|
||||||
|
this.timeout(20 * 1000)
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {PrivateKey}
|
||||||
|
*/
|
||||||
|
let key
|
||||||
|
before(async () => {
|
||||||
|
key = await crypto.keys.generateKeyPair('Ed25519', 512)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a valid key', async () => {
|
||||||
|
expect(key).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
|
||||||
|
const digest = await key.hash()
|
||||||
|
expect(digest).to.have.length(34)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a valid key from seed', async () => {
|
||||||
|
var seed = crypto.randomBytes(32)
|
||||||
|
const seededkey = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512)
|
||||||
|
expect(seededkey).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
|
||||||
|
const digest = await seededkey.hash()
|
||||||
|
expect(digest).to.have.length(34)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates the same key from the same seed', async () => {
|
||||||
|
const seed = crypto.randomBytes(32)
|
||||||
|
const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512)
|
||||||
|
const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512)
|
||||||
|
expect(seededkey1.equals(seededkey2)).to.eql(true)
|
||||||
|
expect(seededkey1.public.equals(seededkey2.public)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates different keys for different seeds', async () => {
|
||||||
|
const seed1 = crypto.randomBytes(32)
|
||||||
|
const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed1, 512)
|
||||||
|
const seed2 = crypto.randomBytes(32)
|
||||||
|
const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed2, 512)
|
||||||
|
expect(seededkey1.equals(seededkey2)).to.eql(false)
|
||||||
|
expect(seededkey1.public.equals(seededkey2.public)).to.eql(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('signs', async () => {
|
||||||
|
const text = crypto.randomBytes(512)
|
||||||
|
const sig = await key.sign(text)
|
||||||
|
const res = await key.public.verify(text, sig)
|
||||||
|
expect(res).to.be.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encoding', async () => {
|
||||||
|
const keyMarshal = key.marshal()
|
||||||
|
const key2 = await ed25519.unmarshalEd25519PrivateKey(keyMarshal)
|
||||||
|
const keyMarshal2 = key2.marshal()
|
||||||
|
|
||||||
|
expect(keyMarshal).to.eql(keyMarshal2)
|
||||||
|
|
||||||
|
const pk = key.public
|
||||||
|
const pkMarshal = pk.marshal()
|
||||||
|
const pk2 = ed25519.unmarshalEd25519PublicKey(pkMarshal)
|
||||||
|
const pkMarshal2 = pk2.marshal()
|
||||||
|
|
||||||
|
expect(pkMarshal).to.eql(pkMarshal2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('key id', async () => {
|
||||||
|
const id = await key.id()
|
||||||
|
expect(id).to.exist()
|
||||||
|
expect(id).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should export a password encrypted libp2p-key', async () => {
|
||||||
|
const key = await crypto.keys.generateKeyPair('Ed25519')
|
||||||
|
const encryptedKey = await key.export('my secret')
|
||||||
|
// Import the key
|
||||||
|
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
|
||||||
|
expect(key.equals(importedKey)).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail to import libp2p-key with wrong password', async () => {
|
||||||
|
const key = await crypto.keys.generateKeyPair('Ed25519')
|
||||||
|
const encryptedKey = await key.export('my secret', 'libp2p-key')
|
||||||
|
try {
|
||||||
|
await crypto.keys.import(encryptedKey, 'not my secret')
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.exist()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expect.fail('should have thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('key equals', () => {
|
||||||
|
it('equals itself', () => {
|
||||||
|
expect(
|
||||||
|
key.equals(key)
|
||||||
|
).to.eql(
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
key.public.equals(key.public)
|
||||||
|
).to.eql(
|
||||||
|
true
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('not equals other key', async () => {
|
||||||
|
const key2 = await crypto.keys.generateKeyPair('Ed25519', 512)
|
||||||
|
expect(key.equals(key2)).to.eql(false)
|
||||||
|
expect(key2.equals(key)).to.eql(false)
|
||||||
|
expect(key.public.equals(key2.public)).to.eql(false)
|
||||||
|
expect(key2.public.equals(key.public)).to.eql(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sign and verify', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const sig = await key.sign(data)
|
||||||
|
const valid = await key.public.verify(data, sig)
|
||||||
|
expect(valid).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails to verify for different data', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const sig = await key.sign(data)
|
||||||
|
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
|
||||||
|
expect(valid).to.be.eql(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('throws error instead of crashing', () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
||||||
|
testGarbage.doTests('key.verify', key.verify.bind(key), 2, null)
|
||||||
|
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys), null, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('go interop', () => {
|
||||||
|
// @ts-check
|
||||||
|
it('verifies with data from go', async () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
||||||
|
const ok = await key.verify(fixtures.verify.data, fixtures.verify.signature)
|
||||||
|
expect(ok).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not include the redundant public key when marshalling privatekey', async () => {
|
||||||
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.redundantPubKey.privateKey)
|
||||||
|
const bytes = key.marshal()
|
||||||
|
expect(bytes.length).to.equal(64)
|
||||||
|
expect(bytes.slice(32)).to.eql(key.public.marshal())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('verifies with data from go with redundant public key', async () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.redundantPubKey.publicKey)
|
||||||
|
const ok = await key.verify(fixtures.redundantPubKey.data, fixtures.redundantPubKey.signature)
|
||||||
|
expect(ok).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates the same signature as go', async () => {
|
||||||
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
|
||||||
|
const sig = await key.sign(fixtures.verify.data)
|
||||||
|
expect(sig).to.eql(fixtures.verify.signature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates the same signature as go with redundant public key', async () => {
|
||||||
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.redundantPubKey.privateKey)
|
||||||
|
const sig = await key.sign(fixtures.redundantPubKey.data)
|
||||||
|
expect(sig).to.eql(fixtures.redundantPubKey.signature)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
77
test/keys/ephemeral-keys.spec.js
Normal file
77
test/keys/ephemeral-keys.spec.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
|
||||||
|
const fixtures = require('../fixtures/go-elliptic-key')
|
||||||
|
const crypto = require('../../src')
|
||||||
|
|
||||||
|
const curves = ['P-256', 'P-384'] // 'P-521' fails in tests :( no clue why
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {Record<string, number>}
|
||||||
|
*/
|
||||||
|
const lengths = {
|
||||||
|
'P-256': 65,
|
||||||
|
'P-384': 97,
|
||||||
|
'P-521': 133
|
||||||
|
}
|
||||||
|
const secretLengths = {
|
||||||
|
'P-256': 32,
|
||||||
|
'P-384': 48,
|
||||||
|
'P-521': 66
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('generateEphemeralKeyPair', () => {
|
||||||
|
curves.forEach((curve) => {
|
||||||
|
it(`generate and shared key ${curve}`, async () => {
|
||||||
|
const keys = await Promise.all([
|
||||||
|
crypto.keys.generateEphemeralKeyPair(curve),
|
||||||
|
crypto.keys.generateEphemeralKeyPair(curve)
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(keys[0].key).to.have.length(lengths[curve])
|
||||||
|
expect(keys[1].key).to.have.length(lengths[curve])
|
||||||
|
|
||||||
|
const shared = await keys[0].genSharedKey(keys[1].key)
|
||||||
|
expect(shared).to.have.length(secretLengths[curve])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('go interop', () => {
|
||||||
|
it('generates a shared secret', async () => {
|
||||||
|
const curve = fixtures.curve
|
||||||
|
|
||||||
|
const keys = await Promise.all([
|
||||||
|
crypto.keys.generateEphemeralKeyPair(curve),
|
||||||
|
crypto.keys.generateEphemeralKeyPair(curve)
|
||||||
|
])
|
||||||
|
|
||||||
|
const alice = keys[0]
|
||||||
|
const bob = keys[1]
|
||||||
|
bob.key = fixtures.bob.public
|
||||||
|
|
||||||
|
const secrets = await Promise.all([
|
||||||
|
alice.genSharedKey(bob.key),
|
||||||
|
bob.genSharedKey(alice.key, fixtures.bob)
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(secrets[0]).to.eql(secrets[1])
|
||||||
|
expect(secrets[0]).to.have.length(32)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles bad curve name', async () => {
|
||||||
|
try {
|
||||||
|
await crypto.keys.generateEphemeralKeyPair('bad name')
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.code).equals('ERR_INVALID_CURVE')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expect.fail('Did not throw error')
|
||||||
|
})
|
||||||
|
})
|
66
test/keys/key-stretcher.spec.js
Normal file
66
test/keys/key-stretcher.spec.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
const { expectErrCode } = require('../util')
|
||||||
|
const crypto = require('../../src')
|
||||||
|
const fixtures = require('../fixtures/go-stretch-key')
|
||||||
|
|
||||||
|
describe('keyStretcher', () => {
|
||||||
|
describe('generate', () => {
|
||||||
|
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
|
||||||
|
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
||||||
|
let res
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {Uint8Array}
|
||||||
|
*/
|
||||||
|
let secret
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
res = await crypto.keys.generateEphemeralKeyPair('P-256')
|
||||||
|
secret = await res.genSharedKey(res.key)
|
||||||
|
})
|
||||||
|
|
||||||
|
ciphers.forEach((cipher) => {
|
||||||
|
hashes.forEach((hash) => {
|
||||||
|
it(`${cipher} - ${hash}`, async () => {
|
||||||
|
const keys = await crypto.keys.keyStretcher(cipher, hash, secret)
|
||||||
|
expect(keys.k1).to.exist()
|
||||||
|
expect(keys.k2).to.exist()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles invalid cipher type', () => {
|
||||||
|
return expectErrCode(crypto.keys.keyStretcher('invalid-cipher', 'SHA256', 'secret'), 'ERR_INVALID_CIPHER_TYPE')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles missing hash type', () => {
|
||||||
|
return expectErrCode(crypto.keys.keyStretcher('AES-128', '', 'secret'), 'ERR_MISSING_HASH_TYPE')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('go interop', () => {
|
||||||
|
fixtures.forEach((test) => {
|
||||||
|
it(`${test.cipher} - ${test.hash}`, async () => {
|
||||||
|
const cipher = test.cipher
|
||||||
|
const hash = test.hash
|
||||||
|
const secret = test.secret
|
||||||
|
const keys = await crypto.keys.keyStretcher(cipher, hash, secret)
|
||||||
|
|
||||||
|
expect(keys.k1.iv).to.be.eql(test.k1.iv)
|
||||||
|
expect(keys.k1.cipherKey).to.be.eql(test.k1.cipherKey)
|
||||||
|
expect(keys.k1.macKey).to.be.eql(test.k1.macKey)
|
||||||
|
|
||||||
|
expect(keys.k2.iv).to.be.eql(test.k2.iv)
|
||||||
|
expect(keys.k2.cipherKey).to.be.eql(test.k2.cipherKey)
|
||||||
|
expect(keys.k2.macKey).to.be.eql(test.k2.macKey)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
53
test/keys/rsa-crypto-libs.js
Normal file
53
test/keys/rsa-crypto-libs.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
/* eslint-env mocha */
|
||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
chai.use(require('chai-string'))
|
||||||
|
|
||||||
|
const LIBS = ['ursa', 'keypair']
|
||||||
|
|
||||||
|
describe('RSA crypto libs', function () {
|
||||||
|
this.timeout(20 * 1000)
|
||||||
|
|
||||||
|
LIBS.forEach(lib => {
|
||||||
|
describe(lib, () => {
|
||||||
|
let crypto
|
||||||
|
let rsa
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
process.env.LP2P_FORCE_CRYPTO_LIB = lib
|
||||||
|
|
||||||
|
for (const path in require.cache) { // clear module cache
|
||||||
|
if (path.endsWith('.js')) {
|
||||||
|
delete require.cache[path]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto = require('../../src')
|
||||||
|
rsa = crypto.keys.supportedKeys.rsa
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a valid key', async () => {
|
||||||
|
const key = await crypto.keys.generateKeyPair('RSA', 512)
|
||||||
|
expect(key).to.be.an.instanceof(rsa.RsaPrivateKey)
|
||||||
|
const digest = await key.hash()
|
||||||
|
expect(digest).to.have.length(34)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
for (const path in require.cache) { // clear module cache
|
||||||
|
if (path.endsWith('.js')) {
|
||||||
|
delete require.cache[path]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete process.env.LP2P_FORCE_CRYPTO_LIB
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
403
test/keys/rsa.spec.js
Normal file
403
test/keys/rsa.spec.js
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
chai.use(require('chai-string'))
|
||||||
|
const { expectErrCode } = require('../util')
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
const crypto = require('../../src')
|
||||||
|
const rsa = crypto.keys.supportedKeys.rsa
|
||||||
|
const fixtures = require('../fixtures/go-key-rsa')
|
||||||
|
|
||||||
|
const testGarbage = require('../helpers/test-garbage-error-handling')
|
||||||
|
|
||||||
|
/** @typedef {import('libp2p-crypto').keys.supportedKeys.rsa.RsaPrivateKey} RsaPrivateKey */
|
||||||
|
|
||||||
|
describe('RSA', function () {
|
||||||
|
this.timeout(20 * 1000)
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {RsaPrivateKey}
|
||||||
|
*/
|
||||||
|
let key
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
key = await rsa.generateKeyPair(512)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a valid key', async () => {
|
||||||
|
expect(key).to.be.an.instanceof(rsa.RsaPrivateKey)
|
||||||
|
const digest = await key.hash()
|
||||||
|
expect(digest).to.have.length(34)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('signs', async () => {
|
||||||
|
const text = key.genSecret()
|
||||||
|
const sig = await key.sign(text)
|
||||||
|
const res = await key.public.verify(text, sig)
|
||||||
|
expect(res).to.be.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encoding', async () => {
|
||||||
|
const keyMarshal = key.marshal()
|
||||||
|
const key2 = await rsa.unmarshalRsaPrivateKey(keyMarshal)
|
||||||
|
const keyMarshal2 = key2.marshal()
|
||||||
|
|
||||||
|
expect(keyMarshal).to.eql(keyMarshal2)
|
||||||
|
|
||||||
|
const pk = key.public
|
||||||
|
const pkMarshal = pk.marshal()
|
||||||
|
const pk2 = rsa.unmarshalRsaPublicKey(pkMarshal)
|
||||||
|
const pkMarshal2 = pk2.marshal()
|
||||||
|
|
||||||
|
expect(pkMarshal).to.eql(pkMarshal2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('key id', async () => {
|
||||||
|
const id = await key.id()
|
||||||
|
expect(id).to.exist()
|
||||||
|
expect(id).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('key equals', () => {
|
||||||
|
it('equals itself', () => {
|
||||||
|
expect(key.equals(key)).to.eql(true)
|
||||||
|
|
||||||
|
expect(key.public.equals(key.public)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('not equals other key', async () => {
|
||||||
|
const key2 = await crypto.keys.generateKeyPair('RSA', 512)
|
||||||
|
expect(key.equals(key2)).to.eql(false)
|
||||||
|
expect(key2.equals(key)).to.eql(false)
|
||||||
|
expect(key.public.equals(key2.public)).to.eql(false)
|
||||||
|
expect(key2.public.equals(key.public)).to.eql(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sign and verify', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const sig = await key.sign(data)
|
||||||
|
const valid = await key.public.verify(data, sig)
|
||||||
|
expect(valid).to.be.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encrypt and decrypt', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const enc = await key.public.encrypt(data)
|
||||||
|
const dec = await key.decrypt(enc)
|
||||||
|
expect(dec).to.be.eql(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encrypt decrypt browser/node interop', async () => {
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {any}
|
||||||
|
*/
|
||||||
|
const id = await crypto.keys.unmarshalPrivateKey(uint8ArrayFromString('CAASqAkwggSkAgEAAoIBAQCk0O+6oNRxhcdZe2GxEDrFBkDV4TZFZnp2ly/dL1cGMBql/8oXPZgei6h7+P5zzfDq2YCfwbjbf0IVY1AshRl6B5VGE1WS+9p1y1OZxJf5os6V1ENnTi6FTcyuBl4BN8dmIKOif0hqgqflaT5OhfYZDXfbJyVQj4vb2+Stu2Xpph3nwqAnTw/7GC/7jrt2Cq6Tu1PoZi36wSwEPYW3eQ1HAYxZjTYYDXl2iyHygnTcbkGRwAQ7vjk+mW7u60zyoolCm9f6Y7c/orJ33DDUocbaGJLlHcfd8bioBwaZy/2m7q43X8pQs0Q1/iwUt0HHZj1YARmHKbh0zR31ciFiV37dAgMBAAECggEADtJBNKnA4QKURj47r0YT2uLwkqtBi6UnDyISalQXAdXyl4n0nPlrhBewC5H9I+HZr+zmTbeIjaiYgz7el1pSy7AB4v7bG7AtWZlyx6mvtwHGjR+8/f3AXjl8Vgv5iSeAdXUq8fJ7SyS7v3wi38HZOzCEXj9bci6ud5ODMYJgLE4gZD0+i1+/V9cpuYfGpS/gLTLEMQLiw/9o8NSZ7sAnxg0UlYhotqaQY23hvXPBOe+0oa95zl2n6XTxCafa3dQl/B6CD1tUq9dhbQew4bxqMq/mhRO9pREEqZ083Uh+u4PTc1BeHgIQaS864pHPb+AY1F7KDvPtHhdojnghp8d70QKBgQDeRYFxo6sd04ohY86Z/i9icVYIyCvfXAKnaMKeGUjK7ou6sDJwFX8W97+CzXpZ/vffsk/l5GGhC50KqrITxHAy/h5IjyDODfps7NMIp0Dm9sO4PWibbw3OOVBRc8w3b3i7I8MrUUA1nLHE1T1HA1rKOTz5jYhE0fi9XKiT1ciKOQKBgQC903w+n9y7M7eaMW7Z5/13kZ7PS3HlM681eaPrk8J4J+c6miFF40/8HOsmarS38v0fgTeKkriPz5A7aLzRHhSiOnp350JNM6c3sLwPEs2qx/CRuWWx1rMERatfDdUH6mvlK6QHu0QgSfQR27EO6a6XvVSJXbvFmimjmtIaz/IpxQKBgQDWJ9HYVAGC81abZTaiWK3/A4QJYhQjWNuVwPICsgnYvI4Uib+PDqcs0ffLZ38DRw48kek5bxpBuJbOuDhro1EXUJCNCJpq7jzixituovd9kTRyR3iKii2bDM2+LPwOTXDdnk9lZRugjCEbrPkleq33Ob7uEtfAty4aBTTHe6uEwQKBgQCB+2q8RyMSXNuADhFlzOFXGrOwJm0bEUUMTPrduRQUyt4e1qOqA3klnXe3mqGcxBpnlEe/76/JacvNom6Ikxx16a0qpYRU8OWz0KU1fR6vrrEgV98241k5t6sdL4+MGA1Bo5xyXtzLb1hdUh3vpDwVU2OrnC+To3iXus/b5EBiMQKBgEI1OaBcFiyjgLGEyFKoZbtzH1mdatTExfrAQqCjOVjQByoMpGhHTXwEaosvyYu63Pa8AJPT7juSGaiKYEJFcXO9BiNyVfmQiqSHJcYeuh+fmO9IlHRHgy5xaIIC00AHS2vC/gXwmXAdPis6BZqDJeiCuOLWJ94QXn8JBT8IgGAI', 'base64pad'))
|
||||||
|
|
||||||
|
const msg = uint8ArrayFromString('hello')
|
||||||
|
|
||||||
|
// browser
|
||||||
|
const dec1 = id.decrypt(uint8ArrayFromString('YRFUDx8UjbWSfDS84cDA4WowaaOmd1qFNAv5QutodCKYb9uPtU/tDiAvJzOGu5DCJRo2J0l/35P2weiB4/C2Cb1aZgXKMx/QQC+2jSJiymhqcZaYerjTvkCFwkjCaqthoVo/YXxsaFZ1q7bdTZUDH1TaJR7hWfSyzyPcA8c0w43MIsw16pY8ZaPSclvnCwhoTg1JGjMk6te3we7+wR8QU7VrPhs54mZWxrpu3NQ8xZ6xQqIedsEiNhBUccrCSzYghgsP0Ae/8iKyGyl3U6IegsJNn8jcocvzOJrmU03rgIFPjvuBdaqB38xDSTjbA123KadB28jNoSZh18q/yH3ZIg==', 'base64pad'))
|
||||||
|
expect(dec1).to.be.eql(msg)
|
||||||
|
// node
|
||||||
|
const dec2 = id.decrypt(uint8ArrayFromString('e6yxssqXsWc27ozDy0PGKtMkCS28KwFyES2Ijz89yiz+w6bSFkNOhHPKplpPzgQEuNoUGdbseKlJFyRYHjIT8FQFBHZM8UgSkgoimbY5on4xSxXs7E5/+twjqKdB7oNveTaTf7JCwaeUYnKSjbiYFEawtMiQE91F8sTT7TmSzOZ48tUhnddAAZ3Ac/O3Z9MSAKOCDipi+JdZtXRT8KimGt36/7hjjosYmPuHR1Xy/yMTL6SMbXtBM3yAuEgbQgP+q/7kHMHji3/JvTpYdIUU+LVtkMusXNasRA+UWG2zAht18vqjFMsm9JTiihZw9jRHD4vxAhf75M992tnC+0ZuQg==', 'base64pad'))
|
||||||
|
expect(dec2).to.be.eql(msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails to verify for different data', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const sig = await key.sign(data)
|
||||||
|
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
|
||||||
|
expect(valid).to.be.eql(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('export and import', () => {
|
||||||
|
it('password protected PKCS #8', async () => {
|
||||||
|
const pem = await key.export('my secret', 'pkcs-8')
|
||||||
|
expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----')
|
||||||
|
const clone = await crypto.keys.import(pem, 'my secret')
|
||||||
|
expect(clone).to.exist()
|
||||||
|
expect(key.equals(clone)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('defaults to PKCS #8', async () => {
|
||||||
|
const pem = await key.export('another secret')
|
||||||
|
expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----')
|
||||||
|
const clone = await crypto.keys.import(pem, 'another secret')
|
||||||
|
expect(clone).to.exist()
|
||||||
|
expect(key.equals(clone)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should export a password encrypted libp2p-key', async () => {
|
||||||
|
const encryptedKey = await key.export('my secret', 'libp2p-key')
|
||||||
|
// Import the key
|
||||||
|
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
|
||||||
|
expect(key.equals(importedKey)).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail to import libp2p-key with wrong password', async () => {
|
||||||
|
const encryptedKey = await key.export('my secret', 'libp2p-key')
|
||||||
|
try {
|
||||||
|
await crypto.keys.import(encryptedKey, 'not my secret')
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.exist()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expect.fail('should have thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('needs correct password', async () => {
|
||||||
|
const pem = await key.export('another secret')
|
||||||
|
try {
|
||||||
|
await crypto.keys.import(pem, 'not the secret')
|
||||||
|
} catch (err) {
|
||||||
|
return // expected
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles invalid export type', () => {
|
||||||
|
return expectErrCode(key.export('secret', 'invalid-type'), 'ERR_INVALID_EXPORT_FORMAT')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('throws error instead of crashing', () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
||||||
|
testGarbage.doTests('key.verify', key.verify.bind(key), 2, true)
|
||||||
|
testGarbage.doTests(
|
||||||
|
'crypto.keys.unmarshalPrivateKey',
|
||||||
|
crypto.keys.unmarshalPrivateKey.bind(crypto.keys),
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('go interop', () => {
|
||||||
|
it('verifies with data from go', async () => {
|
||||||
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
||||||
|
const ok = await key.verify(fixtures.verify.data, fixtures.verify.signature)
|
||||||
|
expect(ok).to.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('openssl interop', () => {
|
||||||
|
it('can read a private key', async () => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:3072
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK
|
||||||
|
0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO
|
||||||
|
v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb
|
||||||
|
ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75
|
||||||
|
Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR
|
||||||
|
xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV
|
||||||
|
CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ
|
||||||
|
+Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0
|
||||||
|
HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA
|
||||||
|
ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo
|
||||||
|
NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo
|
||||||
|
qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5
|
||||||
|
0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv
|
||||||
|
4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT
|
||||||
|
cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL
|
||||||
|
pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW
|
||||||
|
YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB
|
||||||
|
AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c
|
||||||
|
V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB
|
||||||
|
VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v
|
||||||
|
obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl
|
||||||
|
oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL
|
||||||
|
nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr
|
||||||
|
olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU
|
||||||
|
NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz
|
||||||
|
KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW
|
||||||
|
wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4
|
||||||
|
uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT
|
||||||
|
FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY
|
||||||
|
bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI
|
||||||
|
/hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60
|
||||||
|
dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a
|
||||||
|
w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev
|
||||||
|
blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2
|
||||||
|
rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD
|
||||||
|
vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h
|
||||||
|
gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn
|
||||||
|
4pMwXeXP+LO8NIfRXV8mgrm86g==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
const key = await crypto.keys.import(pem, '')
|
||||||
|
expect(key).to.exist()
|
||||||
|
const id = await key.id()
|
||||||
|
expect(id).to.equal('QmfWu2Xp8DZzCkZZzoPB9rcrq4R4RZid6AWE6kmrUAzuHy')
|
||||||
|
})
|
||||||
|
|
||||||
|
// AssertionError: expected 'this only supports pkcs5PBES2' to not exist
|
||||||
|
it.skip('can read a private encrypted key (v1)', async () => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICoTAbBgkqhkiG9w0BBQMwDgQI2563Jugj/KkCAggABIICgPxHkKtUUE8EWevq
|
||||||
|
eX9nTjqpbsv0QoXQMhegfxDELJLU8tj6V0bWNt7QDdfQ1n6FRgnNvNGick6gyqHH
|
||||||
|
yH9qC2oXwkDFP7OrHp2NEZd7DHQLLc+L4KJ/0dzsiZ1U9no7XzQMUay9Bc918ADE
|
||||||
|
pN2/EqigWkaG4gNjkAeKWr6+BNRevDXlSvls7YDboNcTiACi5zJkthivB9g3vT1m
|
||||||
|
gPdN6Gf/mmqtBTDHeqj5QsmXYqeCyo5b26JgYsziABVZDHph4ekPUsTvudRpE9Ex
|
||||||
|
baXwdYEAZxVpSbTvQ3A5qysjSZeM9ttfRTSSwL391q7dViz4+aujpk0Vj7piH+1B
|
||||||
|
CkfO8/XudRdRlnOe+KjMidktKCsMGCIOW92IlfMvIQ/Zn1GTYj9bRXONFNJ2WPND
|
||||||
|
UmCKnL7cmworwg/weRorrGKBWIGspU+tDASOPSvIGKo6Hoxm4CN1TpDRY7DAGlgm
|
||||||
|
Y3TEbMYfpXyzkPjvAhJDt03D3J9PrTO6uM5d7YUaaTmJ2TQFQVF2Lc3Uz8lDJLs0
|
||||||
|
ZYtfQ/4H+YY2RrX7ua7t6ArUcYXZtv0J4lRYWjwV8fGPUVc0d8xLJU0Yjf4BD7K8
|
||||||
|
rsavHo9b5YvBUX7SgUyxAEembEOe3SjQ+gPu2U5wovcjUuC9eItEEsXGrx30BQ0E
|
||||||
|
8BtK2+hp0eMkW5/BYckJkH+Yl8ypbzRGRRIZzLgeI4JveSx/mNhewfgTr+ORPThZ
|
||||||
|
mBdkD5r+ixWF174naw53L8U9wF8kiK7pIE1N9TR4USEeovLwX6Ni/2MMDZedOfof
|
||||||
|
2f77eUdLsK19/5/lcgAAYaXauXWhy2d2r3SayFrC9woy0lh2VLKRMBjcx1oWb7dp
|
||||||
|
0uxzo5Y=
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
const key = await crypto.keys.import(pem, 'mypassword')
|
||||||
|
expect(key).to.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can read a private encrypted key (v2 aes-128-cbc)', async () => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP5QK2RfqUl4CAggA
|
||||||
|
MB0GCWCGSAFlAwQBAgQQj3OyM9gnW2dd/eRHkxjGrgSCAoCpM5GZB0v27cxzZsGc
|
||||||
|
O4/xqgwB0c/bSJ6QogtYU2KVoc7ZNQ5q9jtzn3I4ONvneOkpm9arzYz0FWnJi2C3
|
||||||
|
BPiF0D1NkfvjvMLv56bwiG2A1oBECacyAb2pXYeJY7SdtYKvcbgs3jx65uCm6TF2
|
||||||
|
BylteH+n1ewTQN9DLfASp1n81Ajq9lQGaK03SN2MUtcAPp7N9gnxJrlmDGeqlPRs
|
||||||
|
KpQYRcot+kE6Ew8a5jAr7mAxwpqvr3SM4dMvADZmRQsM4Uc/9+YMUdI52DG87EWc
|
||||||
|
0OUB+fnQ8jw4DZgOE9KKM5/QTWc3aEw/dzXr/YJsrv01oLazhqVHnEMG0Nfr0+DP
|
||||||
|
q+qac1AsCsOb71VxaRlRZcVEkEfAq3gidSPD93qmlDrCnmLYTilcLanXUepda7ez
|
||||||
|
qhjkHtpwBLN5xRZxOn3oUuLGjk8VRwfmFX+RIMYCyihjdmbEDYpNUVkQVYFGi/F/
|
||||||
|
1hxOyl9yhGdL0hb9pKHH10GGIgoqo4jSTLlb4ennihGMHCjehAjLdx/GKJkOWShy
|
||||||
|
V9hj8rAuYnRNb+tUW7ChXm1nLq14x9x1tX0ciVVn3ap/NoMkbFTr8M3pJ4bQlpAn
|
||||||
|
wCT2erYqwQtgSpOJcrFeph9TjIrNRVE7Zlmr7vayJrB/8/oPssVdhf82TXkna4fB
|
||||||
|
PcmO0YWLa117rfdeNM/Duy0ThSdTl39Qd+4FxqRZiHjbt+l0iSa/nOjTv1TZ/QqF
|
||||||
|
wqrO6EtcM45fbFJ1Y79o2ptC2D6MB4HKJq9WCt064/8zQCVx3XPbb3X8Z5o/6koy
|
||||||
|
ePGbz+UtSb9xczvqpRCOiFLh2MG1dUgWuHazjOtUcVWvilKnkjCMzZ9s1qG0sUDj
|
||||||
|
nPyn
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
const key = await crypto.keys.import(pem, 'mypassword')
|
||||||
|
expect(key).to.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can read a private encrypted key (v2 aes-256-cbc)', async () => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -v2 aes-256-cbc -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIhuL894loRucCAggA
|
||||||
|
MB0GCWCGSAFlAwQBKgQQEoEtsjW3iC9/u0uGvkxX7wSCAoAsX3l6JoR2OGbT8CkY
|
||||||
|
YT3RQFqquOgItYOHw6E3tir2YrmxEAo99nxoL8pdto37KSC32eAGnfv5R1zmHHSx
|
||||||
|
0M3/y2AWiCBTX95EEzdtGC1hK3PBa/qpp/xEmcrsjYN6NXxMAkhC0hMP/HdvqMAg
|
||||||
|
ee7upvaYJsJcl8QLFNayAWr8b8cZA/RBhGEIRl59Eyj6nNtxDt3bCrfe06o1CPCV
|
||||||
|
50/fRZEwFOi/C6GYvPN6MrPZO3ALBWgopLT2yQqycTKtfxYWIdOsMBkAjKf2D6Pk
|
||||||
|
u2mqBsaP4b71jIIeT4euSJLsoJV+O39s8YHXtW8GtOqp7V5kIlnm90lZ9wzeLTZ7
|
||||||
|
HJsD/jEdYto5J3YWm2wwEDccraffJSm7UDtJBvQdIx832kxeFCcGQjW38Zl1qqkg
|
||||||
|
iTH1PLTypxj2ZuviS2EkXVFb/kVU6leWwOt6fqWFC58UvJKeCk/6veazz3PDnTWM
|
||||||
|
92ClUqFd+CZn9VT4CIaJaAc6v5NLpPp+T9sRX9AtequPm7FyTeevY9bElfyk9gW9
|
||||||
|
JDKgKxs6DGWDa16RL5vzwtU+G3o6w6IU+mEwa6/c+hN+pRFs/KBNLLSP9OHBx7BJ
|
||||||
|
X/32Ft+VFhJaK+lQ+f+hve7od/bgKnz4c/Vtp7Dh51DgWgCpBgb8p0vqu02vTnxD
|
||||||
|
BXtDv3h75l5PhvdWfVIzpMWRYFvPR+vJi066FjAz2sjYc0NMLSYtZWyWoIInjhoX
|
||||||
|
Dp5CQujCtw/ZSSlwde1DKEWAW4SeDZAOQNvuz0rU3eosNUJxEmh3aSrcrRtDpw+Y
|
||||||
|
mBUuWAZMpz7njBi7h+JDfmSW/GAaMwrVFC2gef5375R0TejAh+COAjItyoeYEvv8
|
||||||
|
DQd8
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
const key = await crypto.keys.import(pem, 'mypassword')
|
||||||
|
expect(key).to.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can read a private encrypted key (v2 des)', async () => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -v2 des -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICwzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQI0lXp62ozXvwCAggA
|
||||||
|
MBEGBSsOAwIHBAiR3Id5vH0u4wSCAoDQQYOrrkPFPIa0S5fQGXnJw1F/66g92Gs1
|
||||||
|
TkGydn4ouabWb++Vbi2chee1oyZsN2l8YNzDi0Gb2PfjsGpg2aJk0a3/efgA0u6T
|
||||||
|
leEH1dA/7Hr9NVspgHkaXpHt3X6wdbznLYJeAelfj7sDXpOkULGWCkCst0Txb6bi
|
||||||
|
Oxv4c0yYykiuUrp+2xvHbF9c2PrcDb58u/OBZcCg3QB1gTugQKM+ZIBRhcTEFLrm
|
||||||
|
8gWbzBfwYiUm6aJce4zoafP0NSlEOBbpbr73A08Q1IK6pISwltOUhhTvspSZnK41
|
||||||
|
y2CHt5Drnpl1pfOw9Q0svO3VrUP+omxP1SFP17ZfaRGw2uHd08HJZs438x5dIQoH
|
||||||
|
QgjlZ8A5rcT3FjnytSh3fln2ZxAGuObghuzmOEL/+8fkGER9QVjmQlsL6OMfB4j4
|
||||||
|
ZAkLf74uaTdegF3SqDQaGUwWgk7LyualmUXWTBoeP9kRIsRQLGzAEmd6duBPypED
|
||||||
|
HhKXP/ZFA1kVp3x1fzJ2llMFB3m1JBwy4PiohqrIJoR+YvKUvzVQtbOjxtCEAj87
|
||||||
|
JFnlQj0wjTd6lfNn+okewMNjKINZx+08ui7XANNU/l18lHIIz3ssXJSmqMW+hRZ9
|
||||||
|
9oB2tntLrnRMhkVZDVHadq7eMFOPu0rkekuaZm9CO2vu4V7Qa2h+gOoeczYza0H7
|
||||||
|
A+qCKbprxyL8SKI5vug2hE+mfC1leXVRtUYm1DnE+oet99bFd0fN20NwTw0rOeRg
|
||||||
|
0Z+/ZpQNizrXxfd3sU7zaJypWCxZ6TD/U/AKBtcb2gqmUjObZhbfbWq6jU2Ye//w
|
||||||
|
EBqQkwAUXR1tNekF8CWLOrfC/wbLRxVRkayb8bQUfdgukLpz0bgw
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
const key = await crypto.keys.import(pem, 'mypassword')
|
||||||
|
expect(key).to.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can read a private encrypted key (v2 des3)', async () => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA
|
||||||
|
MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w
|
||||||
|
2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi
|
||||||
|
wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg
|
||||||
|
SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2
|
||||||
|
dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm
|
||||||
|
kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3
|
||||||
|
Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh
|
||||||
|
hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy
|
||||||
|
qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC
|
||||||
|
TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW
|
||||||
|
3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w
|
||||||
|
6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV
|
||||||
|
NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6
|
||||||
|
DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
const key = await crypto.keys.import(pem, 'mypassword')
|
||||||
|
expect(key).to.exist()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
287
test/keys/secp256k1.spec.js
Normal file
287
test/keys/secp256k1.spec.js
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
const crypto = require('../../src')
|
||||||
|
const secp256k1 = crypto.keys.supportedKeys.secp256k1
|
||||||
|
const keysPBM = crypto.keys.keysPBM
|
||||||
|
const randomBytes = crypto.randomBytes
|
||||||
|
const secp256k1Crypto = require('../../src/keys/secp256k1')(randomBytes)
|
||||||
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||||
|
|
||||||
|
describe('secp256k1 keys', () => {
|
||||||
|
let key
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
key = await secp256k1.generateKeyPair()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a valid key', async () => {
|
||||||
|
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
||||||
|
expect(key.public).to.be.an.instanceof(secp256k1.Secp256k1PublicKey)
|
||||||
|
|
||||||
|
const digest = await key.hash()
|
||||||
|
expect(digest).to.have.length(34)
|
||||||
|
|
||||||
|
const publicDigest = await key.public.hash()
|
||||||
|
expect(publicDigest).to.have.length(34)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('optionally accepts a `bits` argument when generating a key', async () => {
|
||||||
|
const _key = await secp256k1.generateKeyPair()
|
||||||
|
expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('signs', async () => {
|
||||||
|
const text = randomBytes(512)
|
||||||
|
const sig = await key.sign(text)
|
||||||
|
const res = await key.public.verify(text, sig)
|
||||||
|
expect(res).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encoding', async () => {
|
||||||
|
const keyMarshal = key.marshal()
|
||||||
|
const key2 = await secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal)
|
||||||
|
const keyMarshal2 = key2.marshal()
|
||||||
|
|
||||||
|
expect(keyMarshal).to.eql(keyMarshal2)
|
||||||
|
|
||||||
|
const pk = key.public
|
||||||
|
const pkMarshal = pk.marshal()
|
||||||
|
const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal)
|
||||||
|
const pkMarshal2 = pk2.marshal()
|
||||||
|
|
||||||
|
expect(pkMarshal).to.eql(pkMarshal2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('key id', async () => {
|
||||||
|
const id = await key.id()
|
||||||
|
expect(id).to.exist()
|
||||||
|
expect(id).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should export a password encrypted libp2p-key', async () => {
|
||||||
|
const key = await crypto.keys.generateKeyPair('secp256k1')
|
||||||
|
const encryptedKey = await key.export('my secret')
|
||||||
|
// Import the key
|
||||||
|
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
|
||||||
|
expect(key.equals(importedKey)).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail to import libp2p-key with wrong password', async () => {
|
||||||
|
const key = await crypto.keys.generateKeyPair('secp256k1')
|
||||||
|
const encryptedKey = await key.export('my secret', 'libp2p-key')
|
||||||
|
try {
|
||||||
|
await crypto.keys.import(encryptedKey, 'not my secret')
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.exist()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expect.fail('should have thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('key equals', () => {
|
||||||
|
it('equals itself', () => {
|
||||||
|
expect(key.equals(key)).to.eql(true)
|
||||||
|
|
||||||
|
expect(key.public.equals(key.public)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('not equals other key', async () => {
|
||||||
|
const key2 = await secp256k1.generateKeyPair()
|
||||||
|
expect(key.equals(key2)).to.eql(false)
|
||||||
|
expect(key2.equals(key)).to.eql(false)
|
||||||
|
expect(key.public.equals(key2.public)).to.eql(false)
|
||||||
|
expect(key2.public.equals(key.public)).to.eql(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sign and verify', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const sig = await key.sign(data)
|
||||||
|
const valid = await key.public.verify(data, sig)
|
||||||
|
expect(valid).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails to verify for different data', async () => {
|
||||||
|
const data = uint8ArrayFromString('hello world')
|
||||||
|
const sig = await key.sign(data)
|
||||||
|
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
|
||||||
|
expect(valid).to.eql(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('key generation error', () => {
|
||||||
|
let generateKey
|
||||||
|
let secp256k1
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
generateKey = secp256k1Crypto.generateKey
|
||||||
|
secp256k1 = require('../../src/keys/secp256k1-class')(keysPBM, randomBytes, secp256k1Crypto)
|
||||||
|
secp256k1Crypto.generateKey = () => { throw new Error('Error generating key') }
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
secp256k1Crypto.generateKey = generateKey
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns an error if key generation fails', async () => {
|
||||||
|
try {
|
||||||
|
await secp256k1.generateKeyPair()
|
||||||
|
} catch (err) {
|
||||||
|
return expect(err.message).to.equal('Error generating key')
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('handles generation of invalid key', () => {
|
||||||
|
let generateKey
|
||||||
|
let secp256k1
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
generateKey = secp256k1Crypto.generateKey
|
||||||
|
secp256k1 = require('../../src/keys/secp256k1-class')(keysPBM, randomBytes, secp256k1Crypto)
|
||||||
|
secp256k1Crypto.generateKey = () => uint8ArrayFromString('not a real key')
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
secp256k1Crypto.generateKey = generateKey
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns an error if key generator returns an invalid key', async () => {
|
||||||
|
try {
|
||||||
|
await secp256k1.generateKeyPair()
|
||||||
|
} catch (err) {
|
||||||
|
return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32')
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('crypto functions', () => {
|
||||||
|
let privKey
|
||||||
|
let pubKey
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
privKey = await secp256k1Crypto.generateKey()
|
||||||
|
pubKey = secp256k1Crypto.computePublicKey(privKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates valid keys', () => {
|
||||||
|
expect(() => {
|
||||||
|
secp256k1Crypto.validatePrivateKey(privKey)
|
||||||
|
secp256k1Crypto.validatePublicKey(pubKey)
|
||||||
|
}).to.not.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not validate an invalid key', () => {
|
||||||
|
expect(() => secp256k1Crypto.validatePublicKey(uint8ArrayFromString('42'))).to.throw()
|
||||||
|
expect(() => secp256k1Crypto.validatePrivateKey(uint8ArrayFromString('42'))).to.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('validates a correct signature', async () => {
|
||||||
|
const sig = await secp256k1Crypto.hashAndSign(privKey, uint8ArrayFromString('hello'))
|
||||||
|
const valid = await secp256k1Crypto.hashAndVerify(pubKey, sig, uint8ArrayFromString('hello'))
|
||||||
|
expect(valid).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('errors if given a null Uint8Array to sign', async () => {
|
||||||
|
try {
|
||||||
|
await secp256k1Crypto.hashAndSign(privKey, null)
|
||||||
|
} catch (err) {
|
||||||
|
return // expected
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('errors when signing with an invalid key', async () => {
|
||||||
|
try {
|
||||||
|
await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello'))
|
||||||
|
} catch (err) {
|
||||||
|
return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32')
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('errors if given a null Uint8Array to validate', async () => {
|
||||||
|
const sig = await secp256k1Crypto.hashAndSign(privKey, uint8ArrayFromString('hello'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await secp256k1Crypto.hashAndVerify(privKey, sig, null)
|
||||||
|
} catch (err) {
|
||||||
|
return // expected
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('errors when validating a message with an invalid signature', async () => {
|
||||||
|
try {
|
||||||
|
await secp256k1Crypto.hashAndVerify(pubKey, uint8ArrayFromString('invalid-sig'), uint8ArrayFromString('hello'))
|
||||||
|
} catch (err) {
|
||||||
|
return expect(err.message).to.equal('Signature could not be parsed')
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('errors when signing with an invalid key', async () => {
|
||||||
|
try {
|
||||||
|
await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello'))
|
||||||
|
} catch (err) {
|
||||||
|
return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32')
|
||||||
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when compressing an invalid public key', () => {
|
||||||
|
expect(() => secp256k1Crypto.compressPublicKey(uint8ArrayFromString('42'))).to.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws when decompressing an invalid public key', () => {
|
||||||
|
expect(() => secp256k1Crypto.decompressPublicKey(uint8ArrayFromString('42'))).to.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('compresses/decompresses a valid public key', () => {
|
||||||
|
const decompressed = secp256k1Crypto.decompressPublicKey(pubKey)
|
||||||
|
expect(decompressed).to.exist()
|
||||||
|
expect(decompressed.length).to.be.eql(65)
|
||||||
|
const recompressed = secp256k1Crypto.compressPublicKey(decompressed)
|
||||||
|
expect(recompressed).to.eql(pubKey)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('go interop', () => {
|
||||||
|
const fixtures = require('../fixtures/go-key-secp256k1')
|
||||||
|
|
||||||
|
it('loads a private key marshaled by go-libp2p-crypto', async () => {
|
||||||
|
// we need to first extract the key data from the protobuf, which is
|
||||||
|
// normally handled by js-libp2p-crypto
|
||||||
|
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
|
||||||
|
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
|
||||||
|
|
||||||
|
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
|
||||||
|
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
||||||
|
expect(key.bytes).to.eql(fixtures.privateKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('loads a public key marshaled by go-libp2p-crypto', () => {
|
||||||
|
const decoded = keysPBM.PublicKey.decode(fixtures.publicKey)
|
||||||
|
expect(decoded.Type).to.be.eql(keysPBM.KeyType.Secp256k1)
|
||||||
|
|
||||||
|
const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data)
|
||||||
|
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey)
|
||||||
|
expect(key.bytes).to.eql(fixtures.publicKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates the same signature as go-libp2p-crypto', async () => {
|
||||||
|
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
|
||||||
|
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
|
||||||
|
|
||||||
|
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
|
||||||
|
const sig = await key.sign(fixtures.message)
|
||||||
|
expect(sig).to.eql(fixtures.signature)
|
||||||
|
})
|
||||||
|
})
|
3
test/node.js
Normal file
3
test/node.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
require('./keys/rsa-crypto-libs')
|
27
test/random-bytes.spec.js
Normal file
27
test/random-bytes.spec.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
|
||||||
|
const randomBytes = require('../src/random-bytes')
|
||||||
|
|
||||||
|
describe('randomBytes', () => {
|
||||||
|
it('produces random bytes', () => {
|
||||||
|
expect(randomBytes(16)).to.have.length(16)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws if length is 0', () => {
|
||||||
|
expect(() => randomBytes(0)).to.throw(Error).with.property('code', 'ERR_INVALID_LENGTH')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws if length is < 0', () => {
|
||||||
|
expect(() => randomBytes(-1)).to.throw(Error).with.property('code', 'ERR_INVALID_LENGTH')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws if length is not a number', () => {
|
||||||
|
expect(() => randomBytes('hi')).to.throw(Error).with.property('code', 'ERR_INVALID_LENGTH')
|
||||||
|
})
|
||||||
|
})
|
177
test/rsa.spec.js
177
test/rsa.spec.js
@@ -1,177 +0,0 @@
|
|||||||
/* eslint-env mocha */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect
|
|
||||||
|
|
||||||
const crypto = require('../src')
|
|
||||||
const rsa = crypto.keys.rsa
|
|
||||||
const fixtures = require('./fixtures/go-key-rsa')
|
|
||||||
|
|
||||||
describe('RSA', () => {
|
|
||||||
let key
|
|
||||||
before((done) => {
|
|
||||||
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
|
|
||||||
if (err) return done(err)
|
|
||||||
key = _key
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('generates a valid key', (done) => {
|
|
||||||
expect(
|
|
||||||
key
|
|
||||||
).to.be.an.instanceof(
|
|
||||||
rsa.RsaPrivateKey
|
|
||||||
)
|
|
||||||
|
|
||||||
key.hash((err, digest) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(digest).to.have.length(34)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('signs', (done) => {
|
|
||||||
const text = key.genSecret()
|
|
||||||
|
|
||||||
key.sign(text, (err, sig) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
key.public.verify(text, sig, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(res).to.be.eql(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('encoding', (done) => {
|
|
||||||
const keyMarshal = key.marshal()
|
|
||||||
rsa.unmarshalRsaPrivateKey(keyMarshal, (err, key2) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
const keyMarshal2 = key2.marshal()
|
|
||||||
|
|
||||||
expect(
|
|
||||||
keyMarshal
|
|
||||||
).to.be.eql(
|
|
||||||
keyMarshal2
|
|
||||||
)
|
|
||||||
|
|
||||||
const pk = key.public
|
|
||||||
const pkMarshal = pk.marshal()
|
|
||||||
const pk2 = rsa.unmarshalRsaPublicKey(pkMarshal)
|
|
||||||
const pkMarshal2 = pk2.marshal()
|
|
||||||
|
|
||||||
expect(
|
|
||||||
pkMarshal
|
|
||||||
).to.be.eql(
|
|
||||||
pkMarshal2
|
|
||||||
)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('key equals', () => {
|
|
||||||
it('equals itself', () => {
|
|
||||||
expect(
|
|
||||||
key.equals(key)
|
|
||||||
).to.be.eql(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
key.public.equals(key.public)
|
|
||||||
).to.be.eql(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('not equals other key', (done) => {
|
|
||||||
crypto.generateKeyPair('RSA', 2048, (err, key2) => {
|
|
||||||
if (err) return done(err)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
key.equals(key2)
|
|
||||||
).to.be.eql(
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
key2.equals(key)
|
|
||||||
).to.be.eql(
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
key.public.equals(key2.public)
|
|
||||||
).to.be.eql(
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
key2.public.equals(key.public)
|
|
||||||
).to.be.eql(
|
|
||||||
false
|
|
||||||
)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('sign and verify', (done) => {
|
|
||||||
const data = new Buffer('hello world')
|
|
||||||
key.sign(data, (err, sig) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
key.public.verify(data, sig, (err, valid) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
expect(valid).to.be.eql(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fails to verify for different data', (done) => {
|
|
||||||
const data = new Buffer('hello world')
|
|
||||||
key.sign(data, (err, sig) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
key.public.verify(new Buffer('hello'), sig, (err, valid) => {
|
|
||||||
if (err) {
|
|
||||||
return done(err)
|
|
||||||
}
|
|
||||||
expect(valid).to.be.eql(false)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('go interop', () => {
|
|
||||||
it('verifies with data from go', (done) => {
|
|
||||||
const key = crypto.unmarshalPublicKey(fixtures.verify.publicKey)
|
|
||||||
|
|
||||||
key.verify(fixtures.verify.data, fixtures.verify.signature, (err, ok) => {
|
|
||||||
if (err) throw err
|
|
||||||
expect(err).to.not.exist
|
|
||||||
expect(ok).to.be.eql(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
38
test/util.spec.js
Normal file
38
test/util.spec.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
|
/* eslint-env mocha */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const dirtyChai = require('dirty-chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
require('node-forge/lib/jsbn')
|
||||||
|
const forge = require('node-forge/lib/forge')
|
||||||
|
const util = require('../src/util')
|
||||||
|
|
||||||
|
describe('Util', () => {
|
||||||
|
let bn
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
bn = new forge.jsbn.BigInteger('dead', 16)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert BigInteger to a uint base64url encoded string', () => {
|
||||||
|
expect(util.bigIntegerToUintBase64url(bn)).to.eql('3q0')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert BigInteger to a uint base64url encoded string with padding', () => {
|
||||||
|
const bnpad = new forge.jsbn.BigInteger('ff', 16)
|
||||||
|
expect(util.bigIntegerToUintBase64url(bnpad, 2)).to.eql('AP8')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert base64url encoded string to BigInteger', () => {
|
||||||
|
const num = util.base64urlToBigInteger('3q0')
|
||||||
|
expect(num.equals(bn)).to.be.true()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert base64url encoded string to Uint8Array with padding', () => {
|
||||||
|
const buf = util.base64urlToBuffer('AP8', 2)
|
||||||
|
expect(Uint8Array.from([0, 255])).to.eql(buf)
|
||||||
|
})
|
||||||
|
})
|
21
test/util/index.js
Normal file
21
test/util/index.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/* eslint-disable valid-jsdoc */
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {function(any, string): Promise<void>}
|
||||||
|
*/
|
||||||
|
const expectErrCode = async (p, code) => {
|
||||||
|
try {
|
||||||
|
await p
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.have.property('code', code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expect.fail(`Expected error with code ${code} but no error thrown`)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { expectErrCode }
|
30
tsconfig.json
Normal file
30
tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": [
|
||||||
|
"es6"
|
||||||
|
],
|
||||||
|
"target": "ES5",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"libp2p-crypto": [
|
||||||
|
"./src",
|
||||||
|
"../../src",
|
||||||
|
"../src"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"types": ["node", "mocha", "chai"],
|
||||||
|
"noEmit": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"files": ["./src/index.d.ts",],
|
||||||
|
"include": ["./test/**/*.spec.js"]
|
||||||
|
}
|
Reference in New Issue
Block a user