mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-07-22 07:22:12 +00:00
Compare commits
183 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2d15e717e4 | ||
|
6775dbf670 | ||
|
4b09aae8ca | ||
|
764d8bff3e | ||
|
26b6217041 | ||
|
5500ac4a6e | ||
|
d675670ed9 | ||
|
ad7107233e | ||
|
5cd0e8cc1a | ||
|
0ffe31821a | ||
|
7b3625888c | ||
|
b7bce77ad5 | ||
|
c1f867bd9c | ||
|
e3f02eb6f1 | ||
|
a0874389a9 | ||
|
567d68c855 | ||
|
af782c5906 | ||
|
f0593c9e6d | ||
|
8d8294dc3f | ||
|
df23d634c5 | ||
|
88e1bcf75f | ||
|
c54ea206f0 | ||
|
857d2bd902 | ||
|
200110cb9d | ||
|
9e5778694c | ||
|
87e8f1c86f | ||
|
df75980a88 | ||
|
934390acd3 | ||
|
8b80b46667 | ||
|
e8efad546f | ||
|
e8cbf13d85 | ||
|
c7e0409c1c | ||
|
f4c00893ad | ||
|
b05e77f375 | ||
|
ad478454d8 | ||
|
8c69ffb20f | ||
|
e689a402a3 | ||
|
4bd032a6ae | ||
|
50c61ba46e | ||
|
3a90f70350 | ||
|
743c69524c | ||
|
1a347fa04c | ||
|
71339e08e7 | ||
|
0ab2c2d2d6 | ||
|
cdcca5f828 | ||
|
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 | ||
|
1b6a070fa8 | ||
|
1471e07bf9 | ||
|
bc554d1407 | ||
|
83d2d52205 | ||
|
301c779f49 | ||
|
d552fd423a | ||
|
306504c386 | ||
|
bf80e8e511 | ||
|
4e619e60f5 | ||
|
a958f52a5c | ||
|
dfc476c4f6 | ||
|
71eb33a44f | ||
|
310733726e | ||
|
0efc94bd20 | ||
|
68f4b5f496 | ||
|
2f8e234044 | ||
|
c2c6fde394 | ||
|
14dde32177 | ||
|
5bc30297de | ||
|
a5ad8cf444 | ||
|
be64372a5e | ||
|
2b0b7abd78 | ||
|
17f2065d21 | ||
|
2f065167fa | ||
|
e0ecce18ce | ||
|
cea1140ec6 | ||
|
e5b7c1f622 | ||
|
20326199d9 | ||
|
4e56e1724f | ||
|
7d63f698c0 | ||
|
a49df7786c | ||
|
c73adb00cc | ||
|
8a95de4700 | ||
|
c35a65133f | ||
|
4eb4aa05de | ||
|
21f96a4eb7 | ||
|
39b5124526 | ||
|
93e50dde10 | ||
|
e383da5d44 | ||
|
9b687f380c | ||
|
82abede64a | ||
|
a56ab406e4 | ||
|
d753941c6e | ||
|
6022eb0838 | ||
|
1c6d0912cd | ||
|
e18804c31e | ||
|
133a2c8833 | ||
|
fad0865b2b | ||
|
4edef07182 | ||
|
19c6ce7c06 | ||
|
3fa76a874f | ||
|
6e0fd6f257 | ||
|
c91d9b61c8 | ||
|
76eeb5aa18 | ||
|
843b5e33d6 | ||
|
308ac7cd1a | ||
|
6c8f978ea4 | ||
|
b93b410357 | ||
|
99a5245fa3 | ||
|
34856d58ab | ||
|
d59c6af7c0 | ||
|
1683bf1dc8 | ||
|
a4edf8b99b | ||
|
27524354af | ||
|
a1f054ca8e | ||
|
5c61c89391 | ||
|
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 | ||
|
a7c2567ba2 | ||
|
69edfff49b | ||
|
9a0e2585d8 | ||
|
12630dc514 | ||
|
b088bab80f | ||
|
cecadba14d | ||
|
6ebc408f73 | ||
|
08c5df5e79 | ||
|
1cd614237a | ||
|
9795ac0722 | ||
|
73a5258876 | ||
|
c35a988331 |
13
.aegir.js
13
.aegir.js
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
webpack: {
|
||||
resolve: {
|
||||
alias: {
|
||||
'node-forge': path.resolve(__dirname, 'vendor/forge.bundle.js')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
src/keys/keys.proto.js
|
12
.gitignore
vendored
12
.gitignore
vendored
@@ -1,6 +1,11 @@
|
||||
docs
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
**/node_modules/
|
||||
**/*.log
|
||||
test/repo-tests*
|
||||
**/bundle.js
|
||||
|
||||
# Logs
|
||||
logs
|
||||
@@ -33,3 +38,10 @@ node_modules
|
||||
|
||||
lib
|
||||
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
|
63
.travis.yml
63
.travis.yml
@@ -1,34 +1,45 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
|
||||
cache: npm
|
||||
|
||||
stages:
|
||||
- check
|
||||
- test
|
||||
- cov
|
||||
|
||||
node_js:
|
||||
- 4
|
||||
- 5
|
||||
- stable
|
||||
- '10'
|
||||
- '12'
|
||||
|
||||
# Make sure we have new NPM.
|
||||
before_install:
|
||||
- npm install -g npm
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
- npm run coverage
|
||||
script: npx nyc -s npm run test:node -- --bail
|
||||
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: check
|
||||
script:
|
||||
- npx aegir commitlint --travis
|
||||
- npx aegir dep-check
|
||||
- npm run lint
|
||||
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- stage: test
|
||||
name: chrome
|
||||
addons:
|
||||
chrome: stable
|
||||
script:
|
||||
- npx aegir test -t browser
|
||||
|
||||
after_success:
|
||||
- npm run coverage-publish
|
||||
- stage: test
|
||||
name: firefox
|
||||
addons:
|
||||
firefox: latest
|
||||
script:
|
||||
- npx aegir test -t browser -- --browsers FirefoxHeadless
|
||||
|
||||
env:
|
||||
- CXX=g++-4.8
|
||||
|
||||
addons:
|
||||
firefox: 'latest'
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
notifications:
|
||||
email: false
|
||||
|
234
CHANGELOG.md
Normal file
234
CHANGELOG.md
Normal file
@@ -0,0 +1,234 @@
|
||||
<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))
|
||||
|
||||
|
||||
|
239
README.md
239
README.md
@@ -1,35 +1,49 @@
|
||||
# js-libp2p-crypto
|
||||
|
||||
[](http://ipn.io)
|
||||
[](http://ipfs.io/)
|
||||
[](http://webchat.freenode.net/?channels=%23ipfs)
|
||||
[](https://github.com/RichardLitt/standard-readme)
|
||||
[](https://coveralls.io/github/libp2p/js-libp2p-crypto?branch=master)
|
||||
[](https://travis-ci.org/libp2p/js-libp2p-crypto)
|
||||
[](https://circleci.com/gh/libp2p/js-libp2p-crypto)
|
||||
[](http://protocol.ai)
|
||||
[](http://libp2p.io/)
|
||||
[](http://webchat.freenode.net/?channels=%23libp2p)
|
||||
[](https://discuss.libp2p.io)
|
||||
[](https://codecov.io/gh/libp2p/js-libp2p-crypto)
|
||||
[](https://travis-ci.com/libp2p/js-libp2p-crypto)
|
||||
[](https://david-dm.org/libp2p/js-libp2p-crypto)
|
||||
[](https://github.com/feross/standard)
|
||||
|
||||
> Crypto primitives for libp2p in JavaScript
|
||||
|
||||
This repo contains the JavaScript implementation of the crypto primitives
|
||||
needed for libp2p. This is based on this [go implementation](https://github.com/ipfs/go-libp2p-crypto).
|
||||
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).
|
||||
|
||||
## Lead Maintainer
|
||||
|
||||
[Friedel Ziegelmayer](https://github.com/dignifiedquire/)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Install](#install)
|
||||
- [Usage](#usage)
|
||||
- [Example](#example)
|
||||
- [API](#api)
|
||||
- [`generateKeyPair(type, bits)`](#generatekeypairtype-bits)
|
||||
- [`generateEphemeralKeyPair(curve)`](#generateephemeralkeypaircurve)
|
||||
- [`keyStretcher(cipherType, hashType, secret)`](#keystretcherciphertype-hashtype-secret)
|
||||
- [`marshalPublicKey(key[, type])`](#marshalpublickeykey-type)
|
||||
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
|
||||
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
|
||||
- [`unmarshalPrivateKey(buf)`](#unmarshalprivatekeybuf)
|
||||
- [Contribute](#contribute)
|
||||
- [License](#license)
|
||||
- [js-libp2p-crypto](#js-libp2p-crypto)
|
||||
- [Lead Maintainer](#Lead-Maintainer)
|
||||
- [Table of Contents](#Table-of-Contents)
|
||||
- [Install](#Install)
|
||||
- [API](#API)
|
||||
- [`crypto.aes`](#cryptoaes)
|
||||
- [`crypto.aes.create(key, iv)`](#cryptoaescreatekey-iv)
|
||||
- [`decrypt(data)`](#decryptdata)
|
||||
- [`encrypt(data)`](#encryptdata)
|
||||
- [`crypto.hmac`](#cryptohmac)
|
||||
- [`crypto.hmac.create(hash, secret)`](#cryptohmaccreatehash-secret)
|
||||
- [`digest(data)`](#digestdata)
|
||||
- [`crypto.keys`](#cryptokeys)
|
||||
- [`crypto.keys.generateKeyPair(type, bits)`](#cryptokeysgenerateKeyPairtype-bits)
|
||||
- [`crypto.keys.generateEphemeralKeyPair(curve)`](#cryptokeysgenerateEphemeralKeyPaircurve)
|
||||
- [`crypto.keys.keyStretcher(cipherType, hashType, secret)`](#cryptokeyskeyStretchercipherType-hashType-secret)
|
||||
- [`crypto.keys.marshalPublicKey(key, [type])`](#cryptokeysmarshalPublicKeykey-type)
|
||||
- [`crypto.keys.unmarshalPublicKey(buf)`](#cryptokeysunmarshalPublicKeybuf)
|
||||
- [`crypto.keys.marshalPrivateKey(key, [type])`](#cryptokeysmarshalPrivateKeykey-type)
|
||||
- [`crypto.keys.unmarshalPrivateKey(buf)`](#cryptokeysunmarshalPrivateKeybuf)
|
||||
- [`crypto.keys.import(pem, password)`](#cryptokeysimportpem-password)
|
||||
- [`crypto.randomBytes(number)`](#cryptorandomBytesnumber)
|
||||
- [`crypto.pbkdf2(password, salt, iterations, keySize, hash)`](#cryptopbkdf2password-salt-iterations-keySize-hash)
|
||||
- [Contribute](#Contribute)
|
||||
- [License](#License)
|
||||
|
||||
## Install
|
||||
|
||||
@@ -37,34 +51,130 @@ needed for libp2p. This is based on this [go implementation](https://github.com/
|
||||
npm install --save libp2p-crypto
|
||||
```
|
||||
|
||||
## Usage
|
||||
## API
|
||||
|
||||
### Example
|
||||
### `crypto.aes`
|
||||
|
||||
Expoes 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: Buffer` The key, if length `16` then `AES 128` is used. For length `32`, `AES 256` is used.
|
||||
- `iv: Buffer` Must have length `16`.
|
||||
|
||||
Returns `Promise<{decrypt<Function>, encrypt<Function>}>`
|
||||
|
||||
##### `decrypt(data)`
|
||||
|
||||
- `data: Buffer`
|
||||
|
||||
Returns `Promise<Buffer>`
|
||||
|
||||
##### `encrypt(data)`
|
||||
|
||||
- `data: Buffer`
|
||||
|
||||
Returns `Promise<Buffer>`
|
||||
|
||||
```js
|
||||
const crypto = require('libp2p-crypto')
|
||||
|
||||
var keyPair = crypto.generateKeyPair('RSA', 2048)
|
||||
// Setting up Key and IV
|
||||
|
||||
// A 16 bytes array, 128 Bits, AES-128 is chosen
|
||||
const key128 = Buffer.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 = Buffer.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(Buffer.from(decryptedMessage))
|
||||
console.log(encryptedBuffer)
|
||||
// prints: <Buffer 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: <Buffer 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`
|
||||
|
||||
### `generateKeyPair(type, bits)`
|
||||
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.
|
||||
|
||||
- `type: String`, only `'RSA'` is currently supported
|
||||
- `bits: Number`
|
||||
#### `crypto.hmac.create(hash, secret)`
|
||||
|
||||
- `hash: String`
|
||||
- `secret: Buffer`
|
||||
|
||||
Returns `Promise<{digest<Function>}>`
|
||||
|
||||
##### `digest(data)`
|
||||
|
||||
- `data: Buffer`
|
||||
|
||||
Returns `Promise<Buffer>`
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
const crypto = require('libp2p-crypto')
|
||||
|
||||
async function main () {
|
||||
const hash = 'SHA1' // 'SHA256' || 'SHA512'
|
||||
const hmac = await crypto.hmac.create(hash, Buffer.from('secret'))
|
||||
const sig = await hmac.digest(Buffer.from('hello world'))
|
||||
console.log(sig)
|
||||
}
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
### `crypto.keys`
|
||||
|
||||
**Supported Key Types**
|
||||
|
||||
The [`generateKeyPair`](#generatekeypairtype-bits), [`marshalPublicKey`](#marshalpublickeykey-type), and [`marshalPrivateKey`](#marshalprivatekeykey-type) functions accept a string `type` argument.
|
||||
|
||||
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](https://github.com/libp2p/js-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.
|
||||
|
||||
### `crypto.keys.generateKeyPair(type, bits)`
|
||||
|
||||
- `type: String`, see [Supported Key Types](#supported-key-types) above.
|
||||
- `bits: Number` Minimum of 1024
|
||||
|
||||
Returns `Promise<{privateKey<Buffer>, publicKey<Buffer>}>`
|
||||
|
||||
Generates a keypair of the given type and bitsize.
|
||||
|
||||
### `generateEphemeralKeyPair(curve)`
|
||||
### `crypto.keys.generateEphemeralKeyPair(curve)`
|
||||
|
||||
- `curve: String`, one of `'P-256'`, `'P-384'`, `'P-521'` is currently supported
|
||||
|
||||
Returns `Promise`
|
||||
|
||||
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.
|
||||
|
||||
Returns an object of the form
|
||||
Resolves to an object of the form:
|
||||
|
||||
```js
|
||||
{
|
||||
key: Buffer,
|
||||
@@ -72,15 +182,18 @@ Returns an object of the form
|
||||
}
|
||||
```
|
||||
|
||||
### `keyStretcher(cipherType, hashType, secret)`
|
||||
### `crypto.keys.keyStretcher(cipherType, hashType, secret)`
|
||||
|
||||
- `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'`
|
||||
- `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512`
|
||||
- `secret: Buffer`
|
||||
|
||||
Returns `Promise`
|
||||
|
||||
Generates a set of keys for each party by stretching the shared key.
|
||||
|
||||
Returns an object of the form
|
||||
Resolves to an object of the form:
|
||||
|
||||
```js
|
||||
{
|
||||
k1: {
|
||||
@@ -95,35 +208,71 @@ Returns an object of the form
|
||||
}
|
||||
}
|
||||
```
|
||||
### `marshalPublicKey(key[, type])`
|
||||
|
||||
- `key: crypto.rsa.RsaPublicKey`
|
||||
- `type: String`, only `'RSA'` is currently supported
|
||||
### `crypto.keys.marshalPublicKey(key, [type])`
|
||||
|
||||
- `key: keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | require('libp2p-crypto-secp256k1').Secp256k1PublicKey`
|
||||
- `type: String`, see [Supported Key Types](#supported-key-types) above. Defaults to 'rsa'.
|
||||
|
||||
Returns `Buffer`
|
||||
|
||||
Converts a public key object into a protobuf serialized public key.
|
||||
|
||||
### `unmarshalPublicKey(buf)`
|
||||
### `crypto.keys.unmarshalPublicKey(buf)`
|
||||
|
||||
- `buf: Buffer`
|
||||
|
||||
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`
|
||||
- `type: String`, only `'RSA'` is currently supported
|
||||
### `crypto.keys.marshalPrivateKey(key, [type])`
|
||||
|
||||
- `key: keys.rsa.RsaPrivateKey | keys.ed25519.Ed25519PrivateKey | require('libp2p-crypto-secp256k1').Secp256k1PrivateKey`
|
||||
- `type: String`, see [Supported Key Types](#supported-key-types) above.
|
||||
|
||||
Returns `Buffer`
|
||||
|
||||
Converts a private key object into a protobuf serialized private key.
|
||||
|
||||
### `unmarshalPrivateKey(buf)`
|
||||
### `crypto.keys.unmarshalPrivateKey(buf)`
|
||||
|
||||
- `buf: Buffer`
|
||||
|
||||
Converts a protobuf serialized private key into its representative object.
|
||||
Returns `Promise<RsaPrivateKey|Ed25519PrivateKey|Secp256k1PrivateKey>`
|
||||
|
||||
Converts a protobuf serialized private key into its representative object.
|
||||
|
||||
### `crypto.keys.import(pem, password)`
|
||||
|
||||
- `pem: string`
|
||||
- `password: string`
|
||||
|
||||
Returns `Promise<RsaPrivateKey>`
|
||||
|
||||
Converts a PEM password protected private key into its representative object.
|
||||
|
||||
### `crypto.randomBytes(number)`
|
||||
|
||||
- `number: Number`
|
||||
|
||||
Returns `Buffer`
|
||||
|
||||
Generates a Buffer 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
|
||||
|
||||
Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/js-libp2p-crypto/issues)!
|
||||
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)!
|
||||
|
||||
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
|
||||
|
||||
@@ -131,4 +280,4 @@ This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/c
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
[MIT](./LICENSE)
|
||||
|
23
benchmarks/ephemeral-keys.js
Normal file
23
benchmarks/ephemeral-keys.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const Benchmark = require('benchmark')
|
||||
const crypto = require('../src')
|
||||
|
||||
const suite = new Benchmark.Suite('ephemeral-keys')
|
||||
|
||||
const secrets = []
|
||||
const curves = ['P-256', 'P-384', 'P-521']
|
||||
|
||||
curves.forEach((curve) => {
|
||||
suite.add(`ephemeral key with secrect ${curve}`, async (d) => {
|
||||
const res = await crypto.keys.generateEphemeralKeyPair('P-256')
|
||||
const secret = await res.genSharedKey(res.key)
|
||||
secrets.push(secret)
|
||||
d.resolve()
|
||||
}, { defer: true })
|
||||
})
|
||||
|
||||
suite
|
||||
.on('cycle', (event) => console.log(String(event.target)))
|
||||
.run({ async: true })
|
34
benchmarks/key-stretcher.js
Normal file
34
benchmarks/key-stretcher.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const Benchmark = require('benchmark')
|
||||
|
||||
const crypto = require('../src')
|
||||
|
||||
const suite = new Benchmark.Suite('key-stretcher')
|
||||
|
||||
const keys = []
|
||||
|
||||
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
|
||||
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
||||
|
||||
;(async () => {
|
||||
const res = await crypto.keys.generateEphemeralKeyPair('P-256')
|
||||
const secret = await res.genSharedKey(res.key)
|
||||
|
||||
ciphers.forEach((cipher) => hashes.forEach((hash) => {
|
||||
setup(cipher, hash, secret)
|
||||
}))
|
||||
|
||||
suite
|
||||
.on('cycle', (event) => console.log(String(event.target)))
|
||||
.run({ async: true })
|
||||
})()
|
||||
|
||||
function setup (cipher, hash, secret) {
|
||||
suite.add(`keyStretcher ${cipher} ${hash}`, async (d) => {
|
||||
const k = await crypto.keys.keyStretcher(cipher, hash, secret)
|
||||
keys.push(k)
|
||||
d.resolve()
|
||||
}, { defer: true })
|
||||
}
|
37
benchmarks/rsa.js
Normal file
37
benchmarks/rsa.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const Benchmark = require('benchmark')
|
||||
const crypto = require('../src')
|
||||
|
||||
const suite = new Benchmark.Suite('rsa')
|
||||
|
||||
const keys = []
|
||||
const bits = [1024, 2048, 4096]
|
||||
|
||||
bits.forEach((bit) => {
|
||||
suite.add(`generateKeyPair ${bit}bits`, async (d) => {
|
||||
const key = await crypto.keys.generateKeyPair('RSA', bit)
|
||||
keys.push(key)
|
||||
d.resolve()
|
||||
}, {
|
||||
defer: true
|
||||
})
|
||||
})
|
||||
|
||||
suite.add('sign and verify', async (d) => {
|
||||
const key = keys[0]
|
||||
const text = key.genSecret()
|
||||
|
||||
const sig = await key.sign(text)
|
||||
const res = await key.public.verify(text, sig)
|
||||
|
||||
if (res !== true) { throw new Error('failed to verify') }
|
||||
d.resolve()
|
||||
}, {
|
||||
defer: true
|
||||
})
|
||||
|
||||
suite
|
||||
.on('cycle', (event) => console.log(String(event.target)))
|
||||
.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
|
102
package.json
102
package.json
@@ -1,20 +1,31 @@
|
||||
{
|
||||
"name": "libp2p-crypto",
|
||||
"version": "0.6.1",
|
||||
"version": "0.17.0",
|
||||
"description": "Crypto primitives for libp2p",
|
||||
"main": "lib/index.js",
|
||||
"jsnext:main": "src/index.js",
|
||||
"main": "src/index.js",
|
||||
"leadMaintainer": "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||
"browser": {
|
||||
"./src/hmac/index.js": "./src/hmac/index-browser.js",
|
||||
"./src/keys/ecdh.js": "./src/keys/ecdh-browser.js",
|
||||
"./src/aes/ciphers.js": "./src/aes/ciphers-browser.js",
|
||||
"./src/keys/rsa.js": "./src/keys/rsa-browser.js"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "aegir-lint",
|
||||
"build": "aegir-build",
|
||||
"test": "aegir-test",
|
||||
"test:node": "aegir-test --env node",
|
||||
"test:browser": "aegir-test --env browser",
|
||||
"release": "aegir-release",
|
||||
"release-minor": "aegir-release --type minor",
|
||||
"release-major": "aegir-release --type major",
|
||||
"coverage": "aegir-coverage",
|
||||
"coverage-publish": "aegir-coverage publish"
|
||||
"lint": "aegir lint",
|
||||
"build": "aegir build",
|
||||
"build-proto": "pbjs --wrap commonjs --target static-module src/keys/keys.proto > src/keys/keys.proto.js",
|
||||
"test": "aegir test",
|
||||
"test:node": "aegir test -t node",
|
||||
"test:browser": "aegir test -t browser -t webworker",
|
||||
"release": "aegir release",
|
||||
"release-minor": "aegir release --type minor",
|
||||
"release-major": "aegir release --type major",
|
||||
"coverage": "aegir coverage --ignore src/keys/keys.proto.js",
|
||||
"size": "bundlesize -f dist/index.min.js -s 139kB"
|
||||
},
|
||||
"keywords": [
|
||||
"IPFS",
|
||||
@@ -22,38 +33,67 @@
|
||||
"crypto",
|
||||
"rsa"
|
||||
],
|
||||
"author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"elliptic": "^6.2.3",
|
||||
"multihashing": "^0.2.1",
|
||||
"node-forge": "^0.6.39",
|
||||
"protocol-buffers": "^3.1.6"
|
||||
"asmcrypto.js": "^2.3.2",
|
||||
"asn1.js": "^5.0.1",
|
||||
"bn.js": "^5.0.0",
|
||||
"browserify-aes": "^1.2.0",
|
||||
"bs58": "^4.0.1",
|
||||
"iso-random-stream": "^1.1.0",
|
||||
"keypair": "^1.0.1",
|
||||
"libp2p-crypto-secp256k1": "~0.4.0",
|
||||
"multihashing-async": "~0.7.0",
|
||||
"node-forge": "~0.8.5",
|
||||
"pem-jwk": "^2.0.0",
|
||||
"protons": "^1.0.1",
|
||||
"rsa-pem-to-jwk": "^1.1.3",
|
||||
"tweetnacl": "^1.0.1",
|
||||
"ursa-optional": "~0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aegir": "^8.0.0",
|
||||
"chai": "^3.5.0",
|
||||
"pre-commit": "^1.1.3"
|
||||
"aegir": "^19.0.5",
|
||||
"benchmark": "^2.1.4",
|
||||
"bundlesize": "~0.18.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-string": "^1.5.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"sinon": "^7.3.2"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint",
|
||||
"test"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^4.0.0"
|
||||
"node": ">=10.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ipfs/js-libp2p-crypto.git"
|
||||
"url": "https://github.com/libp2p/js-libp2p-crypto.git"
|
||||
},
|
||||
"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": [
|
||||
"Alan Shaw <alan.shaw@protocol.ai>",
|
||||
"Alberto Elias <hi@albertoelias.me>",
|
||||
"Arve Knudsen <arve.knudsen@gmail.com>",
|
||||
"David Dias <daviddias.p@gmail.com>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||
"Greenkeeper <support@greenkeeper.io>",
|
||||
"Hugo Dias <hugomrdias@gmail.com>",
|
||||
"Jack Kleeman <jackkleeman@gmail.com>",
|
||||
"Jacob Heun <jacobheun@gmail.com>",
|
||||
"Joao Santos <jrmsantos15@gmail.com>",
|
||||
"Maciej Krüger <mkg20001@gmail.com>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"greenkeeperio-bot <support@greenkeeper.io>"
|
||||
"Richard Schneider <makaretu@gmail.com>",
|
||||
"Tom Swindell <t.swindell@rubyx.co.uk>",
|
||||
"Vasco Santos <vasco.santos@ua.pt>",
|
||||
"Victor Bjelkholm <victorbjelkholm@gmail.com>",
|
||||
"Yusef Napora <yusef@napora.org>",
|
||||
"dignifiedquire <dignifiedquire@users.noreply.github.com>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>",
|
||||
"nikuda <nikuda@gmail.com>"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
8
src/aes/ciphers-browser.js
Normal file
8
src/aes/ciphers-browser.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict'
|
||||
|
||||
const crypto = require('browserify-aes')
|
||||
|
||||
module.exports = {
|
||||
createCipheriv: crypto.createCipheriv,
|
||||
createDecipheriv: crypto.createDecipheriv
|
||||
}
|
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
|
||||
}
|
34
src/aes/index-browser.js
Normal file
34
src/aes/index-browser.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict'
|
||||
|
||||
const asm = require('asmcrypto.js')
|
||||
|
||||
exports.create = async function (key, iv) { // eslint-disable-line require-await
|
||||
if (key.length !== 16 && key.length !== 32) {
|
||||
throw new Error('Invalid key length')
|
||||
}
|
||||
|
||||
const enc = new asm.AES_CTR.Encrypt({
|
||||
key: key,
|
||||
nonce: iv
|
||||
})
|
||||
const dec = new asm.AES_CTR.Decrypt({
|
||||
key: key,
|
||||
nonce: iv
|
||||
})
|
||||
|
||||
const res = {
|
||||
async encrypt (data) { // eslint-disable-line require-await
|
||||
return Buffer.from(
|
||||
enc.process(data).result
|
||||
)
|
||||
},
|
||||
|
||||
async decrypt (data) { // eslint-disable-line require-await
|
||||
return Buffer.from(
|
||||
dec.process(data).result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
30
src/aes/index.js
Normal file
30
src/aes/index.js
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const ciphers = require('./ciphers')
|
||||
|
||||
const CIPHER_MODES = {
|
||||
16: 'aes-128-ctr',
|
||||
32: 'aes-256-ctr'
|
||||
}
|
||||
|
||||
exports.create = async function (key, iv) { // eslint-disable-line require-await
|
||||
const mode = CIPHER_MODES[key.length]
|
||||
if (!mode) {
|
||||
throw new Error('Invalid key length')
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
enum KeyType {
|
||||
RSA = 0;
|
||||
}
|
||||
|
||||
message PublicKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
|
||||
message PrivateKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const EC = require('elliptic').ec
|
||||
|
||||
const curveMap = {
|
||||
'P-256': 'p256',
|
||||
'P-384': 'p384',
|
||||
'P-521': 'p521'
|
||||
}
|
||||
|
||||
// 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.
|
||||
module.exports = (curveName) => {
|
||||
const curve = curveMap[curveName]
|
||||
if (!curve) {
|
||||
throw new Error('unsupported curve passed')
|
||||
}
|
||||
|
||||
const ec = new EC(curve)
|
||||
|
||||
const priv = ec.genKeyPair()
|
||||
|
||||
// forcePrivate is used for testing only
|
||||
const genSharedKey = (theirPub, forcePrivate) => {
|
||||
const pub = ec.keyFromPublic(theirPub, 'hex')
|
||||
const p = forcePrivate || priv
|
||||
return p.derive(pub.getPublic()).toBuffer('be')
|
||||
}
|
||||
|
||||
return {
|
||||
key: new Buffer(priv.getPublic('hex'), 'hex'),
|
||||
genSharedKey
|
||||
}
|
||||
}
|
36
src/hmac/index-browser.js
Normal file
36
src/hmac/index-browser.js
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict'
|
||||
|
||||
const webcrypto = require('../webcrypto.js')
|
||||
const lengths = require('./lengths')
|
||||
|
||||
const hashTypes = {
|
||||
SHA1: 'SHA-1',
|
||||
SHA256: 'SHA-256',
|
||||
SHA512: 'SHA-512'
|
||||
}
|
||||
|
||||
const sign = async (key, data) => {
|
||||
return Buffer.from(await webcrypto.subtle.sign({ name: 'HMAC' }, key, data))
|
||||
}
|
||||
|
||||
exports.create = async function (hashType, secret) {
|
||||
const hash = hashTypes[hashType]
|
||||
|
||||
const key = await webcrypto.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
|
||||
}
|
7
src/hmac/lengths.js
Normal file
7
src/hmac/lengths.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
SHA1: 20,
|
||||
SHA256: 32,
|
||||
SHA512: 64
|
||||
}
|
83
src/index.js
83
src/index.js
@@ -1,78 +1,11 @@
|
||||
'use strict'
|
||||
|
||||
const protobuf = require('protocol-buffers')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const pbm = protobuf(fs.readFileSync(path.join(__dirname, './crypto.proto')))
|
||||
const hmac = require('./hmac')
|
||||
const aes = require('./aes')
|
||||
const keys = require('./keys')
|
||||
|
||||
exports.utils = require('./utils')
|
||||
const keys = exports.keys = require('./keys')
|
||||
|
||||
exports.keyStretcher = require('./key-stretcher')
|
||||
exports.generateEphemeralKeyPair = require('./ephemeral-keys')
|
||||
|
||||
// Generates a keypair of the given type and bitsize
|
||||
exports.generateKeyPair = (type, bits) => {
|
||||
let key = keys[type.toLowerCase()]
|
||||
if (!key) {
|
||||
throw new Error('invalid or unsupported key type')
|
||||
}
|
||||
|
||||
return key.generateKeyPair(bits)
|
||||
}
|
||||
|
||||
// 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 pbm.PublicKey.encode({
|
||||
Type: pbm.KeyType.RSA,
|
||||
Data: key.marshal()
|
||||
})
|
||||
}
|
||||
|
||||
// Converts a protobuf serialized private key into its
|
||||
// representative object
|
||||
exports.unmarshalPrivateKey = (buf) => {
|
||||
const decoded = pbm.PrivateKey.decode(buf)
|
||||
|
||||
switch (decoded.Type) {
|
||||
case pbm.KeyType.RSA:
|
||||
return keys.rsa.unmarshalRsaPrivateKey(decoded.Data)
|
||||
default:
|
||||
throw 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 pbm.PrivateKey.encode({
|
||||
Type: pbm.KeyType.RSA,
|
||||
Data: key.marshal()
|
||||
})
|
||||
}
|
||||
exports.aes = aes
|
||||
exports.hmac = hmac
|
||||
exports.keys = keys
|
||||
exports.randomBytes = require('./random-bytes')
|
||||
exports.pbkdf2 = require('./pbkdf2')
|
||||
|
@@ -1,95 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const forge = require('node-forge')
|
||||
const createBuffer = forge.util.createBuffer
|
||||
|
||||
const cipherMap = {
|
||||
'AES-128': {
|
||||
ivSize: 16,
|
||||
keySize: 16
|
||||
},
|
||||
'AES-256': {
|
||||
ivSize: 16,
|
||||
keySize: 32
|
||||
},
|
||||
Blowfish: {
|
||||
ivSize: 8,
|
||||
cipherKeySize: 32
|
||||
}
|
||||
}
|
||||
|
||||
const hashMap = {
|
||||
SHA1: 'sha1',
|
||||
SHA256: 'sha256',
|
||||
// workaround for https://github.com/digitalbazaar/forge/issues/401
|
||||
SHA512: forge.md.sha512.create()
|
||||
}
|
||||
|
||||
// Generates a set of keys for each party by stretching the shared key.
|
||||
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
|
||||
module.exports = (cipherType, hashType, secret) => {
|
||||
const cipher = cipherMap[cipherType]
|
||||
const hash = hashMap[hashType]
|
||||
|
||||
if (!cipher) {
|
||||
throw new Error('unkown cipherType passed')
|
||||
}
|
||||
|
||||
if (!hash) {
|
||||
throw new Error('unkown hashType passed')
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(secret)) {
|
||||
secret = createBuffer(secret.toString('binary'))
|
||||
}
|
||||
|
||||
const cipherKeySize = cipher.keySize
|
||||
const ivSize = cipher.ivSize
|
||||
const hmacKeySize = 20
|
||||
const seed = 'key expansion'
|
||||
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
|
||||
|
||||
const m = forge.hmac.create()
|
||||
m.start(hash, secret)
|
||||
m.update(seed)
|
||||
|
||||
let a = m.digest().bytes()
|
||||
const result = createBuffer()
|
||||
|
||||
let j = 0
|
||||
for (; j < resultLength;) {
|
||||
m.start(hash, secret)
|
||||
m.update(a)
|
||||
m.update(seed)
|
||||
|
||||
const b = createBuffer(m.digest(), 'raw')
|
||||
let todo = b.length()
|
||||
|
||||
if (j + todo > resultLength) {
|
||||
todo = resultLength - j
|
||||
}
|
||||
|
||||
result.putBytes(b.getBytes(todo))
|
||||
|
||||
j += todo
|
||||
|
||||
m.start(hash, secret)
|
||||
m.update(a)
|
||||
a = m.digest().bytes()
|
||||
}
|
||||
|
||||
const half = resultLength / 2
|
||||
const r1 = createBuffer(result.getBytes(half))
|
||||
const r2 = createBuffer(result.getBytes())
|
||||
|
||||
const createKey = (res) => ({
|
||||
iv: new Buffer(res.getBytes(ivSize), 'binary'),
|
||||
cipherKey: new Buffer(res.getBytes(cipherKeySize), 'binary'),
|
||||
macKey: new Buffer(res.getBytes(), 'binary')
|
||||
})
|
||||
|
||||
return {
|
||||
k1: createKey(r1),
|
||||
k2: createKey(r2)
|
||||
}
|
||||
}
|
117
src/keys/ecdh-browser.js
Normal file
117
src/keys/ecdh-browser.js
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict'
|
||||
|
||||
const webcrypto = require('../webcrypto.js')
|
||||
const BN = require('asn1.js').bignum
|
||||
const { toBase64, toBn } = require('../util')
|
||||
|
||||
const bits = {
|
||||
'P-256': 256,
|
||||
'P-384': 384,
|
||||
'P-521': 521
|
||||
}
|
||||
|
||||
exports.generateEphmeralKeyPair = async function (curve) {
|
||||
const pair = await webcrypto.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.subtle.importKey(
|
||||
'jwk',
|
||||
unmarshalPrivateKey(curve, forcePrivate),
|
||||
{
|
||||
name: 'ECDH',
|
||||
namedCurve: curve
|
||||
},
|
||||
false,
|
||||
['deriveBits']
|
||||
)
|
||||
} else {
|
||||
privateKey = pair.privateKey
|
||||
}
|
||||
|
||||
const keys = [
|
||||
await webcrypto.subtle.importKey(
|
||||
'jwk',
|
||||
unmarshalPublicKey(curve, theirPub),
|
||||
{
|
||||
name: 'ECDH',
|
||||
namedCurve: curve
|
||||
},
|
||||
false,
|
||||
[]
|
||||
),
|
||||
privateKey
|
||||
]
|
||||
|
||||
return Buffer.from(await webcrypto.subtle.deriveBits(
|
||||
{
|
||||
name: 'ECDH',
|
||||
namedCurve: curve,
|
||||
public: keys[0]
|
||||
},
|
||||
keys[1],
|
||||
bits[curve]
|
||||
))
|
||||
}
|
||||
|
||||
const publicKey = await webcrypto.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 Buffer.concat([
|
||||
Buffer.from([4]), // uncompressed point
|
||||
toBn(jwk.x).toArrayLike(Buffer, 'be', byteLen),
|
||||
toBn(jwk.y).toArrayLike(Buffer, '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.from([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, byteLen),
|
||||
y: toBase64(y, byteLen),
|
||||
ext: true
|
||||
}
|
||||
}
|
||||
|
||||
function unmarshalPrivateKey (curve, key) {
|
||||
const result = unmarshalPublicKey(curve, key.public)
|
||||
result.d = toBase64(new BN(key.private))
|
||||
return result
|
||||
}
|
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 curves = {
|
||||
'P-256': 'prime256v1',
|
||||
'P-384': 'secp384r1',
|
||||
'P-521': 'secp521r1'
|
||||
}
|
||||
|
||||
exports.generateEphmeralKeyPair = async function (curve) { // eslint-disable-line require-await
|
||||
if (!curves[curve]) {
|
||||
throw new Error(`Unkown curve: ${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)
|
||||
}
|
||||
}
|
||||
}
|
132
src/keys/ed25519-class.js
Normal file
132
src/keys/ed25519-class.js
Normal file
@@ -0,0 +1,132 @@
|
||||
'use strict'
|
||||
|
||||
const multihashing = require('multihashing-async')
|
||||
const protobuf = require('protons')
|
||||
const bs58 = require('bs58')
|
||||
|
||||
const crypto = require('./ed25519')
|
||||
const pbm = protobuf(require('./keys.proto'))
|
||||
|
||||
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 Buffer.from(this._key)
|
||||
}
|
||||
|
||||
get bytes () {
|
||||
return pbm.PublicKey.encode({
|
||||
Type: pbm.KeyType.Ed25519,
|
||||
Data: this.marshal()
|
||||
})
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
async hash () { // eslint-disable-line require-await
|
||||
return multihashing(this.bytes, 'sha2-256')
|
||||
}
|
||||
}
|
||||
|
||||
class Ed25519PrivateKey {
|
||||
// key - 64 byte Uint8Array or Buffer containing private key
|
||||
// publicKey - 32 byte Uint8Array or Buffer 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 () {
|
||||
if (!this._publicKey) {
|
||||
throw new Error('public key not provided')
|
||||
}
|
||||
|
||||
return new Ed25519PublicKey(this._publicKey)
|
||||
}
|
||||
|
||||
marshal () {
|
||||
return Buffer.concat([Buffer.from(this._key), Buffer.from(this._publicKey)])
|
||||
}
|
||||
|
||||
get bytes () {
|
||||
return pbm.PrivateKey.encode({
|
||||
Type: pbm.KeyType.Ed25519,
|
||||
Data: this.marshal()
|
||||
})
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
async hash () { // eslint-disable-line require-await
|
||||
return 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 bs58.encode(hash)
|
||||
}
|
||||
}
|
||||
|
||||
function unmarshalEd25519PrivateKey (bytes) {
|
||||
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)
|
||||
}
|
||||
|
||||
function unmarshalEd25519PublicKey (bytes) {
|
||||
bytes = ensureKey(bytes, crypto.publicKeyLength)
|
||||
return new Ed25519PublicKey(bytes)
|
||||
}
|
||||
|
||||
async function generateKeyPair () {
|
||||
const { secretKey, publicKey } = await crypto.generateKey()
|
||||
return new Ed25519PrivateKey(secretKey, publicKey)
|
||||
}
|
||||
|
||||
async function generateKeyPairFromSeed (seed) {
|
||||
const { secretKey, publicKey } = await crypto.generateKeyFromSeed(seed)
|
||||
return new Ed25519PrivateKey(secretKey, publicKey)
|
||||
}
|
||||
|
||||
function ensureKey (key, length) {
|
||||
if (Buffer.isBuffer(key)) {
|
||||
key = new Uint8Array(key)
|
||||
}
|
||||
if (!(key instanceof Uint8Array) || key.length !== length) {
|
||||
throw new Error('Key must be a Uint8Array or Buffer of length ' + length)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Ed25519PublicKey,
|
||||
Ed25519PrivateKey,
|
||||
unmarshalEd25519PrivateKey,
|
||||
unmarshalEd25519PublicKey,
|
||||
generateKeyPair,
|
||||
generateKeyPairFromSeed
|
||||
}
|
23
src/keys/ed25519.js
Normal file
23
src/keys/ed25519.js
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
const nacl = require('tweetnacl')
|
||||
|
||||
exports.publicKeyLength = nacl.sign.publicKeyLength
|
||||
exports.privateKeyLength = nacl.sign.secretKeyLength
|
||||
|
||||
exports.generateKey = async function () { // eslint-disable-line require-await
|
||||
return nacl.sign.keyPair()
|
||||
}
|
||||
|
||||
// seed should be a 32 byte uint8array
|
||||
exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line require-await
|
||||
return nacl.sign.keyPair.fromSeed(seed)
|
||||
}
|
||||
|
||||
exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
|
||||
return Buffer.from(nacl.sign.detached(msg, key))
|
||||
}
|
||||
|
||||
exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await
|
||||
return nacl.sign.detached.verify(msg, sig, key)
|
||||
}
|
9
src/keys/ephemeral-keys.js
Normal file
9
src/keys/ephemeral-keys.js
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const ecdh = require('./ecdh')
|
||||
|
||||
// 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.
|
||||
module.exports = async (curve) => ecdh.generateEphmeralKeyPair(curve) // eslint-disable-line require-await
|
@@ -1,5 +1,125 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
rsa: require('./rsa')
|
||||
const protobuf = require('protons')
|
||||
const keysPBM = protobuf(require('./keys.proto'))
|
||||
require('node-forge/lib/asn1')
|
||||
require('node-forge/lib/rsa')
|
||||
require('node-forge/lib/pbe')
|
||||
const forge = require('node-forge/lib/forge')
|
||||
|
||||
exports = module.exports
|
||||
|
||||
const supportedKeys = {
|
||||
rsa: require('./rsa-class'),
|
||||
ed25519: require('./ed25519-class'),
|
||||
secp256k1: require('libp2p-crypto-secp256k1')(keysPBM, require('../random-bytes'))
|
||||
}
|
||||
|
||||
exports.supportedKeys = supportedKeys
|
||||
exports.keysPBM = keysPBM
|
||||
|
||||
function isValidKeyType (keyType) {
|
||||
const key = supportedKeys[keyType.toLowerCase()]
|
||||
return key !== undefined
|
||||
}
|
||||
|
||||
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
|
||||
let key = supportedKeys[type.toLowerCase()]
|
||||
|
||||
if (!key) {
|
||||
throw new Error('invalid or unsupported key type')
|
||||
}
|
||||
|
||||
return key.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
|
||||
let key = supportedKeys[type.toLowerCase()]
|
||||
if (!key) {
|
||||
throw new Error('invalid or unsupported key type')
|
||||
}
|
||||
if (type.toLowerCase() !== 'ed25519') {
|
||||
throw new Error('Seed key derivation is unimplemented for RSA or secp256k1')
|
||||
}
|
||||
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 new Error('secp256k1 support requires libp2p-crypto-secp256k1 package')
|
||||
}
|
||||
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()
|
||||
if (!isValidKeyType(type)) {
|
||||
throw new Error('invalid or unsupported key 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 new Error('secp256k1 support requires libp2p-crypto-secp256k1 package')
|
||||
}
|
||||
default:
|
||||
throw 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()
|
||||
if (!isValidKeyType(type)) {
|
||||
throw new Error('invalid or unsupported key type')
|
||||
}
|
||||
|
||||
return key.bytes
|
||||
}
|
||||
|
||||
exports.import = async (pem, password) => { // eslint-disable-line require-await
|
||||
const key = forge.pki.decryptRsaPrivateKey(pem, password)
|
||||
if (key === null) {
|
||||
throw new Error('Cannot read the key, most likely the password is wrong or not a RSA key')
|
||||
}
|
||||
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
|
||||
der = Buffer.from(der.getBytes(), 'binary')
|
||||
return supportedKeys.rsa.unmarshalRsaPrivateKey(der)
|
||||
}
|
||||
|
73
src/keys/key-stretcher.js
Normal file
73
src/keys/key-stretcher.js
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict'
|
||||
|
||||
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) {
|
||||
throw new Error('unkown cipherType passed')
|
||||
}
|
||||
|
||||
if (!hash) {
|
||||
throw 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)
|
||||
|
||||
const m = await hmac.create(hash, secret)
|
||||
let a = await m.digest(seed)
|
||||
|
||||
let result = []
|
||||
let j = 0
|
||||
|
||||
while (j < resultLength) {
|
||||
const b = await m.digest(Buffer.concat([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 = 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)
|
||||
})
|
||||
|
||||
return {
|
||||
k1: createKey(r1),
|
||||
k2: createKey(r2)
|
||||
}
|
||||
}
|
15
src/keys/keys.proto.js
Normal file
15
src/keys/keys.proto.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = `enum KeyType {
|
||||
RSA = 0;
|
||||
Ed25519 = 1;
|
||||
Secp256k1 = 2;
|
||||
}
|
||||
message PublicKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
message PrivateKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}`
|
122
src/keys/rsa-browser.js
Normal file
122
src/keys/rsa-browser.js
Normal file
@@ -0,0 +1,122 @@
|
||||
'use strict'
|
||||
|
||||
const webcrypto = require('../webcrypto.js')
|
||||
const randomBytes = require('../random-bytes')
|
||||
|
||||
exports.utils = require('./rsa-utils')
|
||||
|
||||
exports.generateKey = async function (bits) {
|
||||
const pair = await webcrypto.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.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.subtle.importKey(
|
||||
'jwk',
|
||||
key,
|
||||
{
|
||||
name: 'RSASSA-PKCS1-v1_5',
|
||||
hash: { name: 'SHA-256' }
|
||||
},
|
||||
false,
|
||||
['sign']
|
||||
)
|
||||
|
||||
const sig = await webcrypto.subtle.sign(
|
||||
{ name: 'RSASSA-PKCS1-v1_5' },
|
||||
privateKey,
|
||||
Uint8Array.from(msg)
|
||||
)
|
||||
|
||||
return Buffer.from(sig)
|
||||
}
|
||||
|
||||
exports.hashAndVerify = async function (key, sig, msg) {
|
||||
const publicKey = await webcrypto.subtle.importKey(
|
||||
'jwk',
|
||||
key,
|
||||
{
|
||||
name: 'RSASSA-PKCS1-v1_5',
|
||||
hash: { name: 'SHA-256' }
|
||||
},
|
||||
false,
|
||||
['verify']
|
||||
)
|
||||
|
||||
return webcrypto.subtle.verify(
|
||||
{ name: 'RSASSA-PKCS1-v1_5' },
|
||||
publicKey,
|
||||
sig,
|
||||
msg
|
||||
)
|
||||
}
|
||||
|
||||
function exportKey (pair) {
|
||||
return Promise.all([
|
||||
webcrypto.subtle.exportKey('jwk', pair.privateKey),
|
||||
webcrypto.subtle.exportKey('jwk', pair.publicKey)
|
||||
])
|
||||
}
|
||||
|
||||
function derivePublicFromPrivate (jwKey) {
|
||||
return webcrypto.subtle.importKey(
|
||||
'jwk',
|
||||
{
|
||||
kty: jwKey.kty,
|
||||
n: jwKey.n,
|
||||
e: jwKey.e
|
||||
},
|
||||
{
|
||||
name: 'RSASSA-PKCS1-v1_5',
|
||||
hash: { name: 'SHA-256' }
|
||||
},
|
||||
true,
|
||||
['verify']
|
||||
)
|
||||
}
|
161
src/keys/rsa-class.js
Normal file
161
src/keys/rsa-class.js
Normal file
@@ -0,0 +1,161 @@
|
||||
'use strict'
|
||||
|
||||
const multihashing = require('multihashing-async')
|
||||
const protobuf = require('protons')
|
||||
const bs58 = require('bs58')
|
||||
|
||||
const crypto = require('./rsa')
|
||||
const pbm = protobuf(require('./keys.proto'))
|
||||
require('node-forge/lib/sha512')
|
||||
require('node-forge/lib/pbe')
|
||||
const forge = require('node-forge/lib/forge')
|
||||
|
||||
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 this._key.encrypt(bytes, 'RSAES-PKCS1-V1_5')
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
async hash () { // eslint-disable-line require-await
|
||||
return multihashing(this.bytes, 'sha2-256')
|
||||
}
|
||||
}
|
||||
|
||||
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(16)
|
||||
}
|
||||
|
||||
async sign (message) { // eslint-disable-line require-await
|
||||
return crypto.hashAndSign(this._key, message)
|
||||
}
|
||||
|
||||
get public () {
|
||||
if (!this._publicKey) {
|
||||
throw new Error('public key not provided')
|
||||
}
|
||||
|
||||
return new RsaPublicKey(this._publicKey)
|
||||
}
|
||||
|
||||
marshal () {
|
||||
return crypto.utils.jwkToPkcs1(this._key)
|
||||
}
|
||||
|
||||
get bytes () {
|
||||
return pbm.PrivateKey.encode({
|
||||
Type: pbm.KeyType.RSA,
|
||||
Data: this.marshal()
|
||||
})
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
async hash () { // eslint-disable-line require-await
|
||||
return 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 bs58.encode(hash)
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the key into a password protected PEM format
|
||||
*
|
||||
* @param {string} password - The password to read the encrypted PEM
|
||||
* @param {string} [format] - Defaults to 'pkcs-8'.
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async export (password, format = 'pkcs-8') { // eslint-disable-line require-await
|
||||
let pem = null
|
||||
|
||||
const buffer = new forge.util.ByteBuffer(this.marshal())
|
||||
const asn1 = forge.asn1.fromDer(buffer)
|
||||
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
|
||||
|
||||
if (format === 'pkcs-8') {
|
||||
const options = {
|
||||
algorithm: 'aes256',
|
||||
count: 10000,
|
||||
saltSize: 128 / 8,
|
||||
prfAlgorithm: 'sha512'
|
||||
}
|
||||
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
|
||||
} else {
|
||||
throw new Error(`Unknown export format '${format}'`)
|
||||
}
|
||||
|
||||
return pem
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
114
src/keys/rsa-utils.js
Normal file
114
src/keys/rsa-utils.js
Normal file
@@ -0,0 +1,114 @@
|
||||
'use strict'
|
||||
|
||||
const asn1 = require('asn1.js')
|
||||
|
||||
const util = require('./../util')
|
||||
const toBase64 = util.toBase64
|
||||
const toBn = util.toBn
|
||||
|
||||
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')
|
||||
}
|
176
src/keys/rsa.js
176
src/keys/rsa.js
@@ -1,141 +1,69 @@
|
||||
'use strict'
|
||||
|
||||
const forge = require('node-forge')
|
||||
const protobuf = require('protocol-buffers')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const crypto = require('crypto')
|
||||
const randomBytes = require('../random-bytes')
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
const pki = forge.pki
|
||||
const rsa = pki.rsa
|
||||
|
||||
const pbm = protobuf(fs.readFileSync(path.join(__dirname, '../crypto.proto')))
|
||||
|
||||
class RsaPublicKey {
|
||||
constructor (k) {
|
||||
this._key = k
|
||||
let keypair
|
||||
try {
|
||||
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'keypair') {
|
||||
throw new Error('Force keypair usage')
|
||||
}
|
||||
|
||||
verify (data, sig) {
|
||||
const md = forge.md.sha256.create()
|
||||
if (Buffer.isBuffer(data)) {
|
||||
md.update(data.toString('binary'), 'binary')
|
||||
} else {
|
||||
md.update(data)
|
||||
}
|
||||
|
||||
return this._key.verify(md.digest().bytes(), sig)
|
||||
}
|
||||
|
||||
marshal () {
|
||||
return new Buffer(forge.asn1.toDer(pki.publicKeyToAsn1(this._key)).bytes(), 'binary')
|
||||
}
|
||||
|
||||
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 () {
|
||||
return utils.keyHash(this.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
class RsaPrivateKey {
|
||||
constructor (privKey, pubKey) {
|
||||
this._privateKey = privKey
|
||||
if (pubKey) {
|
||||
this._publicKey = pubKey
|
||||
} else {
|
||||
this._publicKey = forge.pki.setRsaPublicKey(privKey.n, privKey.e)
|
||||
const ursa = require('ursa-optional') // throws if not compiled
|
||||
keypair = ({ bits }) => {
|
||||
const key = ursa.generatePrivateKey(bits)
|
||||
return {
|
||||
private: key.toPrivatePem(),
|
||||
public: key.toPublicPem()
|
||||
}
|
||||
}
|
||||
|
||||
genSecret () {
|
||||
return forge.random.getBytesSync(16)
|
||||
} catch (e) {
|
||||
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'ursa') {
|
||||
throw e
|
||||
}
|
||||
|
||||
sign (message) {
|
||||
const md = forge.md.sha256.create()
|
||||
if (Buffer.isBuffer(message)) {
|
||||
md.update(message.toString('binary'), 'binary')
|
||||
} else {
|
||||
md.update(message)
|
||||
keypair = require('keypair')
|
||||
}
|
||||
const pemToJwk = require('pem-jwk').pem2jwk
|
||||
const jwkToPem = require('pem-jwk').jwk2pem
|
||||
|
||||
exports.utils = require('./rsa-utils')
|
||||
|
||||
exports.generateKey = async function (bits) { // eslint-disable-line require-await
|
||||
const key = keypair({ bits })
|
||||
return {
|
||||
privateKey: pemToJwk(key.private),
|
||||
publicKey: pemToJwk(key.public)
|
||||
}
|
||||
}
|
||||
|
||||
// Takes a jwk key
|
||||
exports.unmarshalPrivateKey = async function (key) { // eslint-disable-line require-await
|
||||
if (!key) {
|
||||
throw new Error('Key is invalid')
|
||||
}
|
||||
return {
|
||||
privateKey: key,
|
||||
publicKey: {
|
||||
kty: key.kty,
|
||||
n: key.n,
|
||||
e: key.e
|
||||
}
|
||||
const raw = this._privateKey.sign(md, 'RSASSA-PKCS1-V1_5')
|
||||
return new Buffer(raw, 'binary')
|
||||
}
|
||||
|
||||
get public () {
|
||||
if (!this._publicKey) {
|
||||
throw new Error('public key not provided')
|
||||
}
|
||||
|
||||
return new RsaPublicKey(this._publicKey)
|
||||
}
|
||||
|
||||
decrypt (bytes) {
|
||||
return this._privateKey.decrypt(bytes, 'RSAES-PKCS1-V1_5')
|
||||
}
|
||||
|
||||
marshal () {
|
||||
return new Buffer(forge.asn1.toDer(pki.privateKeyToAsn1(this._privateKey)).bytes(), 'binary')
|
||||
}
|
||||
|
||||
get bytes () {
|
||||
return pbm.PrivateKey.encode({
|
||||
Type: pbm.KeyType.RSA,
|
||||
Data: this.marshal()
|
||||
})
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
hash () {
|
||||
return utils.keyHash(this.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
function unmarshalRsaPrivateKey (bytes) {
|
||||
if (Buffer.isBuffer(bytes)) {
|
||||
bytes = forge.util.createBuffer(bytes.toString('binary'))
|
||||
}
|
||||
const key = pki.privateKeyFromAsn1(forge.asn1.fromDer(bytes))
|
||||
exports.getRandomValues = randomBytes
|
||||
|
||||
return new RsaPrivateKey(key)
|
||||
exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
|
||||
const sign = crypto.createSign('RSA-SHA256')
|
||||
sign.update(msg)
|
||||
const pem = jwkToPem(key)
|
||||
return sign.sign(pem)
|
||||
}
|
||||
|
||||
function unmarshalRsaPublicKey (bytes) {
|
||||
if (Buffer.isBuffer(bytes)) {
|
||||
bytes = forge.util.createBuffer(bytes.toString('binary'))
|
||||
}
|
||||
const key = pki.publicKeyFromAsn1(forge.asn1.fromDer(bytes))
|
||||
|
||||
return new RsaPublicKey(key)
|
||||
}
|
||||
|
||||
function generateKeyPair (bits) {
|
||||
const p = rsa.generateKeyPair({bits})
|
||||
return new RsaPrivateKey(p.privateKey, p.publicKey)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RsaPublicKey,
|
||||
RsaPrivateKey,
|
||||
unmarshalRsaPublicKey,
|
||||
unmarshalRsaPrivateKey,
|
||||
generateKeyPair
|
||||
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)
|
||||
}
|
||||
|
43
src/pbkdf2.js
Normal file
43
src/pbkdf2.js
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict'
|
||||
|
||||
const forgePbkdf2 = require('node-forge/lib/pbkdf2')
|
||||
const forgeUtil = require('node-forge/lib/util')
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
throw new Error(`Hash '${hash}' is unknown or not supported`)
|
||||
}
|
||||
const dek = forgePbkdf2(
|
||||
password,
|
||||
salt,
|
||||
iterations,
|
||||
keySize,
|
||||
hasher)
|
||||
return forgeUtil.encode64(dek)
|
||||
}
|
||||
|
||||
module.exports = pbkdf2
|
9
src/random-bytes.js
Normal file
9
src/random-bytes.js
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
const randomBytes = require('iso-random-stream/src/random')
|
||||
|
||||
module.exports = function (number) {
|
||||
if (!number || typeof number !== 'number') {
|
||||
throw new Error('first argument must be a Number bigger than 0')
|
||||
}
|
||||
return randomBytes(number)
|
||||
}
|
20
src/util.js
Normal file
20
src/util.js
Normal file
@@ -0,0 +1,20 @@
|
||||
'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, len) {
|
||||
// if len is defined then the bytes are leading-0 padded to the length
|
||||
let s = bn.toArrayLike(Buffer, 'be', len).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,8 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const multihashing = require('multihashing')
|
||||
|
||||
// Hashes a key
|
||||
exports.keyHash = (bytes) => {
|
||||
return multihashing(bytes, 'sha2-256')
|
||||
}
|
5
src/webcrypto.js
Normal file
5
src/webcrypto.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/* global self */
|
||||
|
||||
'use strict'
|
||||
|
||||
module.exports = self.crypto || self.msCrypto
|
153
stats.md
Normal file
153
stats.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Stats
|
||||
|
||||
## Size
|
||||
|
||||
| | non-minified | minified |
|
||||
|-------|--------------|----------|
|
||||
|before | `1.8M` | `949K` |
|
||||
|after | `606K` | `382K` |
|
||||
|
||||
## Performance
|
||||
|
||||
### RSA
|
||||
|
||||
#### Before
|
||||
|
||||
##### Node `6.6.0`
|
||||
|
||||
```
|
||||
generateKeyPair 1024bits x 3.51 ops/sec ±29.45% (22 runs sampled)
|
||||
generateKeyPair 2048bits x 0.17 ops/sec ±145.40% (5 runs sampled)
|
||||
generateKeyPair 4096bits x 0.02 ops/sec ±96.53% (5 runs sampled)
|
||||
sign and verify x 95.98 ops/sec ±1.51% (71 runs sampled)
|
||||
```
|
||||
|
||||
##### Browser (Chrome `53.0.2785.116`)
|
||||
|
||||
```
|
||||
generateKeyPair 1024bits x 3.56 ops/sec ±27.16% (23 runs sampled)
|
||||
generateKeyPair 2048bits x 0.49 ops/sec ±69.32% (8 runs sampled)
|
||||
generateKeyPair 4096bits x 0.03 ops/sec ±77.11% (5 runs sampled)
|
||||
sign and verify x 109 ops/sec ±2.00% (53 runs sampled)
|
||||
```
|
||||
|
||||
#### After
|
||||
|
||||
##### Node `6.6.0`
|
||||
|
||||
```
|
||||
generateKeyPair 1024bits x 42.45 ops/sec ±9.87% (52 runs sampled)
|
||||
generateKeyPair 2048bits x 7.46 ops/sec ±23.80% (16 runs sampled)
|
||||
generateKeyPair 4096bits x 1.50 ops/sec ±58.59% (13 runs sampled)
|
||||
sign and verify x 1,080 ops/sec ±2.23% (74 runs sampled)
|
||||
```
|
||||
|
||||
##### Browser (Chrome `53.0.2785.116`)
|
||||
|
||||
```
|
||||
generateKeyPair 1024bits x 5.89 ops/sec ±18.94% (19 runs sampled)
|
||||
generateKeyPair 2048bits x 1.32 ops/sec ±36.84% (10 runs sampled)
|
||||
generateKeyPair 4096bits x 0.20 ops/sec ±62.49% (5 runs sampled)
|
||||
sign and verify x 608 ops/sec ±6.75% (56 runs sampled)
|
||||
```
|
||||
|
||||
### Key Stretcher
|
||||
|
||||
|
||||
#### Before
|
||||
|
||||
##### Node `6.6.0`
|
||||
|
||||
```
|
||||
keyStretcher AES-128 SHA1 x 3,863 ops/sec ±3.80% (70 runs sampled)
|
||||
keyStretcher AES-128 SHA256 x 3,862 ops/sec ±5.33% (64 runs sampled)
|
||||
keyStretcher AES-128 SHA512 x 3,369 ops/sec ±1.73% (73 runs sampled)
|
||||
keyStretcher AES-256 SHA1 x 3,008 ops/sec ±4.81% (67 runs sampled)
|
||||
keyStretcher AES-256 SHA256 x 2,900 ops/sec ±7.01% (64 runs sampled)
|
||||
keyStretcher AES-256 SHA512 x 2,553 ops/sec ±4.45% (73 runs sampled)
|
||||
keyStretcher Blowfish SHA1 x 28,045 ops/sec ±7.32% (61 runs sampled)
|
||||
keyStretcher Blowfish SHA256 x 18,860 ops/sec ±5.36% (67 runs sampled)
|
||||
keyStretcher Blowfish SHA512 x 12,142 ops/sec ±12.44% (72 runs sampled)
|
||||
```
|
||||
|
||||
##### Browser (Chrome `53.0.2785.116`)
|
||||
|
||||
```
|
||||
keyStretcher AES-128 SHA1 x 4,168 ops/sec ±4.08% (49 runs sampled)
|
||||
keyStretcher AES-128 SHA256 x 4,239 ops/sec ±6.36% (48 runs sampled)
|
||||
keyStretcher AES-128 SHA512 x 3,600 ops/sec ±5.15% (51 runs sampled)
|
||||
keyStretcher AES-256 SHA1 x 3,009 ops/sec ±6.82% (48 runs sampled)
|
||||
keyStretcher AES-256 SHA256 x 3,086 ops/sec ±9.56% (19 runs sampled)
|
||||
keyStretcher AES-256 SHA512 x 2,470 ops/sec ±2.22% (54 runs sampled)
|
||||
keyStretcher Blowfish SHA1 x 7,143 ops/sec ±15.17% (9 runs sampled)
|
||||
keyStretcher Blowfish SHA256 x 17,846 ops/sec ±4.74% (46 runs sampled)
|
||||
keyStretcher Blowfish SHA512 x 7,726 ops/sec ±1.81% (50 runs sampled)
|
||||
```
|
||||
|
||||
#### After
|
||||
|
||||
##### Node `6.6.0`
|
||||
|
||||
```
|
||||
keyStretcher AES-128 SHA1 x 6,680 ops/sec ±3.62% (65 runs sampled)
|
||||
keyStretcher AES-128 SHA256 x 8,124 ops/sec ±4.37% (66 runs sampled)
|
||||
keyStretcher AES-128 SHA512 x 11,683 ops/sec ±4.56% (66 runs sampled)
|
||||
keyStretcher AES-256 SHA1 x 5,531 ops/sec ±4.69% (68 runs sampled)
|
||||
keyStretcher AES-256 SHA256 x 6,725 ops/sec ±4.87% (66 runs sampled)
|
||||
keyStretcher AES-256 SHA512 x 9,042 ops/sec ±3.87% (64 runs sampled)
|
||||
keyStretcher Blowfish SHA1 x 40,757 ops/sec ±5.38% (60 runs sampled)
|
||||
keyStretcher Blowfish SHA256 x 41,845 ops/sec ±4.89% (64 runs sampled)
|
||||
keyStretcher Blowfish SHA512 x 42,345 ops/sec ±4.86% (63 runs sampled)
|
||||
```
|
||||
|
||||
##### Browser (Chrome `53.0.2785.116`)
|
||||
|
||||
```
|
||||
keyStretcher AES-128 SHA1 x 479 ops/sec ±2.12% (54 runs sampled)
|
||||
keyStretcher AES-128 SHA256 x 668 ops/sec ±2.02% (53 runs sampled)
|
||||
keyStretcher AES-128 SHA512 x 1,112 ops/sec ±1.61% (54 runs sampled)
|
||||
keyStretcher AES-256 SHA1 x 460 ops/sec ±1.37% (54 runs sampled)
|
||||
keyStretcher AES-256 SHA256 x 596 ops/sec ±1.56% (54 runs sampled)
|
||||
keyStretcher AES-256 SHA512 x 808 ops/sec ±3.27% (52 runs sampled)
|
||||
keyStretcher Blowfish SHA1 x 3,015 ops/sec ±3.51% (52 runs sampled)
|
||||
keyStretcher Blowfish SHA256 x 2,755 ops/sec ±3.82% (53 runs sampled)
|
||||
keyStretcher Blowfish SHA512 x 2,955 ops/sec ±5.35% (51 runs sampled)
|
||||
```
|
||||
|
||||
### Ephemeral Keys
|
||||
|
||||
#### Before
|
||||
|
||||
##### Node `6.6.0`
|
||||
|
||||
```
|
||||
ephemeral key with secrect P-256 x 89.93 ops/sec ±39.45% (72 runs sampled)
|
||||
ephemeral key with secrect P-384 x 110 ops/sec ±1.28% (71 runs sampled)
|
||||
ephemeral key with secrect P-521 x 112 ops/sec ±1.70% (72 runs sampled)
|
||||
```
|
||||
|
||||
##### Browser (Chrome `53.0.2785.116`)
|
||||
|
||||
```
|
||||
ephemeral key with secrect P-256 x 6.27 ops/sec ±15.89% (35 runs sampled)
|
||||
ephemeral key with secrect P-384 x 6.84 ops/sec ±1.21% (35 runs sampled)
|
||||
ephemeral key with secrect P-521 x 6.60 ops/sec ±1.84% (34 runs sampled)
|
||||
```
|
||||
|
||||
#### After
|
||||
|
||||
##### Node `6.6.0`
|
||||
|
||||
```
|
||||
ephemeral key with secrect P-256 x 555 ops/sec ±1.61% (75 runs sampled)
|
||||
ephemeral key with secrect P-384 x 547 ops/sec ±4.40% (68 runs sampled)
|
||||
ephemeral key with secrect P-521 x 583 ops/sec ±4.84% (72 runs sampled)
|
||||
```
|
||||
|
||||
##### Browser (Chrome `53.0.2785.116`)
|
||||
|
||||
```
|
||||
ephemeral key with secrect P-256 x 796 ops/sec ±2.36% (53 runs sampled)
|
||||
ephemeral key with secrect P-384 x 788 ops/sec ±2.66% (53 runs sampled)
|
||||
ephemeral key with secrect P-521 x 808 ops/sec ±1.83% (54 runs sampled)
|
||||
```
|
97
test/aes/aes.spec.js
Normal file
97
test/aes/aes.spec.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/* 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/aes')
|
||||
const goFixtures = require('./../fixtures/go-aes')
|
||||
|
||||
const bytes = {
|
||||
16: 'AES-128',
|
||||
32: 'AES-256'
|
||||
}
|
||||
|
||||
describe('AES-CTR', () => {
|
||||
Object.keys(bytes).forEach((byte) => {
|
||||
it(`${bytes[byte]} - encrypt and decrypt`, async () => {
|
||||
const key = Buffer.alloc(parseInt(byte, 10))
|
||||
key.fill(5)
|
||||
|
||||
const iv = Buffer.alloc(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 = Buffer.alloc(parseInt(byte, 10))
|
||||
key.fill(5)
|
||||
|
||||
const iv = Buffer.alloc(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 = Buffer.from(rawIn)
|
||||
const output = Buffer.from(fixtures[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)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Object.keys(bytes).forEach((byte) => {
|
||||
if (!goFixtures[byte]) {
|
||||
return
|
||||
}
|
||||
|
||||
it(`${bytes[byte]} - go interop - encrypt and decrypt`, async () => {
|
||||
const key = Buffer.alloc(parseInt(byte, 10))
|
||||
key.fill(5)
|
||||
|
||||
const iv = Buffer.alloc(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 = Buffer.from(rawIn)
|
||||
const output = Buffer.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)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function encryptAndDecrypt (cipher) {
|
||||
const data = Buffer.alloc(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)
|
||||
}
|
114
test/crypto.spec.js
Normal file
114
test/crypto.spec.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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')
|
||||
|
||||
describe('libp2p-crypto', function () {
|
||||
this.timeout(20 * 1000)
|
||||
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)
|
||||
})
|
||||
|
||||
// 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(fixtures.public.key.equals(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', () => {
|
||||
expect(() => crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'shaX-xxx')).to.throw()
|
||||
})
|
||||
})
|
||||
|
||||
describe('randomBytes', () => {
|
||||
it('throws with no number passed', () => {
|
||||
expect(() => {
|
||||
crypto.randomBytes()
|
||||
}).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,44 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const expect = require('chai').expect
|
||||
const EC = require('elliptic').ec
|
||||
|
||||
const crypto = require('../src')
|
||||
const fixtures = require('./fixtures/go-elliptic-key')
|
||||
|
||||
describe('generateEphemeralKeyPair', () => {
|
||||
it('returns a function that generates a shared secret', () => {
|
||||
const res = crypto.generateEphemeralKeyPair('P-256')
|
||||
const ourPublic = '044374add0df35706db7dade25f3959fc051d2ef5166f8a6a0aa632d0ab41cdb4d30e1a064e121ac56155235a6b8d4c5d8fe35e019f507f4e2ff1445e229d7af43'
|
||||
|
||||
expect(
|
||||
res.genSharedKey(ourPublic)
|
||||
).to.have.length(32)
|
||||
|
||||
expect(
|
||||
res.key
|
||||
).to.exist
|
||||
})
|
||||
|
||||
describe('go interop', () => {
|
||||
it('generates a shared secret', () => {
|
||||
const curve = fixtures.curve
|
||||
const ec = new EC(fixtures.curveJs)
|
||||
const bobPrivate = ec.keyFromPrivate(fixtures.bob.private, 'binary')
|
||||
|
||||
const alice = crypto.generateEphemeralKeyPair(curve)
|
||||
const bob = {
|
||||
key: fixtures.bob.public,
|
||||
// this is using bobs private key from go ipfs
|
||||
// instead of alices
|
||||
genSharedKey: (key) => alice.genSharedKey(key, bobPrivate)
|
||||
}
|
||||
|
||||
const s1 = alice.genSharedKey(bob.key)
|
||||
const s2 = bob.genSharedKey(alice.key)
|
||||
|
||||
expect(s1.equals(s2)).to.be.eql(true)
|
||||
})
|
||||
})
|
||||
})
|
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]
|
||||
]
|
||||
}
|
||||
}
|
11
test/fixtures/go-elliptic-key.js
vendored
11
test/fixtures/go-elliptic-key.js
vendored
@@ -2,13 +2,12 @@
|
||||
|
||||
module.exports = {
|
||||
curve: 'P-256',
|
||||
curveJs: 'p256',
|
||||
bob: {
|
||||
private: [
|
||||
231, 236, 69, 16, 13, 92, 76, 83, 75, 40, 32, 71, 235, 187, 29, 214, 98, 231, 42, 5, 80, 89, 58, 175, 8, 95, 86, 50, 44, 214, 4, 172
|
||||
],
|
||||
public: new Buffer([
|
||||
4, 160, 169, 215, 85, 152, 11, 209, 69, 105, 17, 51, 49, 83, 214, 171, 157, 73, 165, 85, 28, 196, 161, 234, 87, 149, 139, 76, 123, 37, 174, 194, 67, 167, 18, 34, 164, 35, 171, 164, 238, 141, 199, 206, 86, 130, 183, 88, 63, 121, 110, 150, 229, 10, 213, 176, 181, 1, 98, 20, 246, 85, 212, 200, 229
|
||||
private: Buffer.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
|
||||
]),
|
||||
public: Buffer.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
|
||||
])
|
||||
}
|
||||
}
|
||||
|
28
test/fixtures/go-key-ed25519.js
vendored
Normal file
28
test/fixtures/go-key-ed25519.js
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
// These were generated in a gore (https://github.com/motemen/gore) repl session:
|
||||
//
|
||||
// :import github.com/libp2p/go-libp2p-crypto
|
||||
// :import crypto/rand
|
||||
// priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
// pubkeyBytes, err := pub.Bytes()
|
||||
// privkeyBytes, err := priv.Bytes()
|
||||
// data := []byte("hello! and welcome to some awesome crypto primitives")
|
||||
// sig, err := priv.Sign(data)
|
||||
//
|
||||
// :import io/ioutil
|
||||
// ioutil.WriteFile("/tmp/pubkey_go.bin", pubkeyBytes, 0644)
|
||||
// // etc..
|
||||
//
|
||||
// Then loaded into a node repl and dumped to arrays with:
|
||||
//
|
||||
// var pubkey = Array.from(fs.readFileSync('/tmp/pubkey_go.bin'))
|
||||
// console.log(JSON.stringify(pubkey))
|
||||
verify: {
|
||||
privateKey: Buffer.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: Buffer.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: Buffer.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: Buffer.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])
|
||||
}
|
||||
}
|
19
test/fixtures/go-key-rsa.js
vendored
19
test/fixtures/go-key-rsa.js
vendored
@@ -2,19 +2,30 @@
|
||||
|
||||
module.exports = {
|
||||
private: {
|
||||
hash: new Buffer([
|
||||
hash: Buffer.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
|
||||
]),
|
||||
key: new Buffer([
|
||||
key: Buffer.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
|
||||
])
|
||||
},
|
||||
public: {
|
||||
hash: new Buffer([
|
||||
hash: Buffer.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
|
||||
]),
|
||||
key: new Buffer([
|
||||
key: Buffer.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
|
||||
])
|
||||
},
|
||||
verify: {
|
||||
signature: Buffer.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
|
||||
]),
|
||||
data: Buffer.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
|
||||
]),
|
||||
publicKey: Buffer.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
|
||||
])
|
||||
}
|
||||
}
|
||||
|
14
test/fixtures/go-stretch-key.js
vendored
14
test/fixtures/go-stretch-key.js
vendored
@@ -3,28 +3,28 @@
|
||||
module.exports = [{
|
||||
cipher: 'AES-256',
|
||||
hash: 'SHA256',
|
||||
secret: new Buffer([
|
||||
secret: Buffer.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
|
||||
]),
|
||||
k1: {
|
||||
iv: new Buffer([
|
||||
iv: Buffer.from([
|
||||
208, 132, 203, 169, 253, 52, 40, 83, 161, 91, 17, 71, 33, 136, 67, 96
|
||||
]),
|
||||
cipherKey: new Buffer([
|
||||
cipherKey: Buffer.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
|
||||
]),
|
||||
macKey: new Buffer([
|
||||
macKey: Buffer.from([
|
||||
6, 179, 91, 245, 224, 56, 153, 120, 77, 140, 29, 5, 15, 213, 187, 65, 137, 230, 202, 120
|
||||
])
|
||||
},
|
||||
k2: {
|
||||
iv: new Buffer([
|
||||
iv: Buffer.from([
|
||||
236, 17, 34, 141, 90, 106, 197, 56, 197, 184, 157, 135, 91, 88, 112, 19
|
||||
]),
|
||||
cipherKey: new Buffer([
|
||||
cipherKey: Buffer.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
|
||||
]),
|
||||
macKey: new Buffer([
|
||||
macKey: Buffer.from([
|
||||
3, 229, 77, 212, 241, 217, 23, 113, 220, 126, 38, 255, 18, 117, 108, 205, 198, 89, 1, 236
|
||||
])
|
||||
}
|
||||
|
8
test/fixtures/secp256k1.js
vendored
Normal file
8
test/fixtures/secp256k1.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
// protobuf marshaled key pair generated with libp2p-crypto-secp256k1
|
||||
// and marshaled with libp2p-crypto.marshalPublicKey / marshalPrivateKey
|
||||
pbmPrivateKey: Buffer.from('08021220e0600103010000000100000000000000be1dc82c2e000000e8d6030301000000', 'hex'),
|
||||
pbmPublicKey: Buffer.from('0802122103a9a7272a726fa083abf31ba44037f8347fbc5e5d3113d62a7c6bc26752fd8ee1', 'hex')
|
||||
}
|
40
test/helpers/test-garbage-error-handling.js
Normal file
40
test/helpers/test-garbage-error-handling.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const util = require('util')
|
||||
const garbage = [Buffer.from('00010203040506070809', 'hex'), {}, null, false, undefined, true, 1, 0, Buffer.from(''), 'aGVsbG93b3JsZA==', 'helloworld', '']
|
||||
|
||||
function doTests (fncName, fnc, num, skipBuffersAndStrings) {
|
||||
if (!num) {
|
||||
num = 1
|
||||
}
|
||||
|
||||
garbage.forEach((garbage) => {
|
||||
if (skipBuffersAndStrings && (Buffer.isBuffer(garbage) || (typeof garbage) === 'string')) {
|
||||
// skip this garbage because it's a buffer or a string and we were told do do that
|
||||
return
|
||||
}
|
||||
let 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 = (obj, fncs, num) => {
|
||||
describe('returns error via cb instead of crashing', () => {
|
||||
fncs.forEach(fnc => {
|
||||
doTests(fnc, obj[fnc], num)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.doTests = doTests
|
22
test/hmac/hmac.spec.js
Normal file
22
test/hmac/hmac.spec.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/* 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 hashes = ['SHA1', 'SHA256', 'SHA512']
|
||||
|
||||
describe('HMAC', () => {
|
||||
hashes.forEach((hash) => {
|
||||
it(`${hash} - sign and verify`, async () => {
|
||||
const hmac = await crypto.hmac.create(hash, Buffer.from('secret'))
|
||||
const sig = await hmac.digest(Buffer.from('hello world'))
|
||||
expect(sig).to.have.length(hmac.length)
|
||||
})
|
||||
})
|
||||
})
|
@@ -1,70 +0,0 @@
|
||||
/* 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(() => {
|
||||
key = crypto.generateKeyPair('RSA', 2048)
|
||||
})
|
||||
|
||||
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', () => {
|
||||
const key2 = crypto.unmarshalPrivateKey(crypto.marshalPrivateKey(key))
|
||||
|
||||
expect(key2.equals(key)).to.be.eql(true)
|
||||
})
|
||||
|
||||
describe('go interop', () => {
|
||||
it('unmarshals private key', () => {
|
||||
const key = crypto.unmarshalPrivateKey(fixtures.private.key)
|
||||
const hash = fixtures.private.hash
|
||||
|
||||
expect(
|
||||
key.hash()
|
||||
).to.be.eql(
|
||||
hash
|
||||
)
|
||||
})
|
||||
|
||||
it('unmarshals public key', () => {
|
||||
const key = crypto.unmarshalPublicKey(fixtures.public.key)
|
||||
const hash = fixtures.public.hash
|
||||
|
||||
expect(
|
||||
key.hash()
|
||||
).to.be.eql(
|
||||
hash
|
||||
)
|
||||
})
|
||||
|
||||
it('unmarshal -> marshal, private key', () => {
|
||||
const key = crypto.unmarshalPrivateKey(fixtures.private.key)
|
||||
const marshalled = crypto.marshalPrivateKey(key)
|
||||
expect(
|
||||
fixtures.private.key.equals(marshalled)
|
||||
).to.be.eql(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
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
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
144
test/keys/ed25519.spec.js
Normal file
144
test/keys/ed25519.spec.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/* 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 ed25519 = crypto.keys.supportedKeys.ed25519
|
||||
const fixtures = require('../fixtures/go-key-ed25519')
|
||||
|
||||
const testGarbage = require('../helpers/test-garbage-error-handling')
|
||||
|
||||
describe('ed25519', function () {
|
||||
this.timeout(20 * 1000)
|
||||
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')
|
||||
})
|
||||
|
||||
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 = Buffer.from('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 = Buffer.from('hello world')
|
||||
const sig = await key.sign(data)
|
||||
const valid = await key.public.verify(Buffer.from('hello'), sig)
|
||||
expect(valid).to.be.eql(false)
|
||||
})
|
||||
|
||||
describe('returns error via cb instead of crashing', () => {
|
||||
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
||||
testGarbage.doTests('key.verify', key.verify.bind(key), 2)
|
||||
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
|
||||
})
|
||||
|
||||
describe('go interop', () => {
|
||||
let privateKey
|
||||
|
||||
before(async () => {
|
||||
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
|
||||
privateKey = key
|
||||
})
|
||||
|
||||
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('generates the same signature as go', async () => {
|
||||
const sig = await privateKey.sign(fixtures.verify.data)
|
||||
expect(sig).to.eql(fixtures.verify.signature)
|
||||
})
|
||||
})
|
||||
})
|
63
test/keys/ephemeral-keys.spec.js
Normal file
63
test/keys/ephemeral-keys.spec.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
@@ -2,24 +2,31 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const expect = require('chai').expect
|
||||
|
||||
const crypto = require('../src')
|
||||
const fixtures = require('./fixtures/go-stretch-key')
|
||||
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-stretch-key')
|
||||
|
||||
describe('keyStretcher', () => {
|
||||
describe('generate', () => {
|
||||
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
|
||||
const hashes = ['SHA1', 'SHA256', 'SHA512']
|
||||
const res = crypto.generateEphemeralKeyPair('P-256')
|
||||
const secret = res.genSharedKey(res.key)
|
||||
let res
|
||||
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}`, () => {
|
||||
const keys = crypto.keyStretcher(cipher, hash, secret)
|
||||
expect(keys.k1).to.exist
|
||||
expect(keys.k2).to.exist
|
||||
it(`${cipher} - ${hash}`, async () => {
|
||||
const keys = await crypto.keys.keyStretcher(cipher, hash, secret)
|
||||
expect(keys.k1).to.exist()
|
||||
expect(keys.k2).to.exist()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -27,11 +34,11 @@ describe('keyStretcher', () => {
|
||||
|
||||
describe('go interop', () => {
|
||||
fixtures.forEach((test) => {
|
||||
it(`${test.cipher} - ${test.hash}`, () => {
|
||||
it(`${test.cipher} - ${test.hash}`, async () => {
|
||||
const cipher = test.cipher
|
||||
const hash = test.hash
|
||||
const secret = test.secret
|
||||
const keys = crypto.keyStretcher(cipher, hash, 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)
|
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
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
344
test/keys/rsa.spec.js
Normal file
344
test/keys/rsa.spec.js
Normal file
@@ -0,0 +1,344 @@
|
||||
/* 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 crypto = require('../../src')
|
||||
const rsa = crypto.keys.supportedKeys.rsa
|
||||
const fixtures = require('../fixtures/go-key-rsa')
|
||||
|
||||
const testGarbage = require('../helpers/test-garbage-error-handling')
|
||||
|
||||
describe('RSA', function () {
|
||||
this.timeout(20 * 1000)
|
||||
let key
|
||||
|
||||
before(async () => {
|
||||
key = await crypto.keys.generateKeyPair('RSA', 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 = Buffer.from('hello world')
|
||||
const sig = await key.sign(data)
|
||||
const valid = await key.public.verify(data, sig)
|
||||
expect(valid).to.be.eql(true)
|
||||
})
|
||||
|
||||
it('fails to verify for different data', async () => {
|
||||
const data = Buffer.from('hello world')
|
||||
const sig = await key.sign(data)
|
||||
const valid = await key.public.verify(Buffer.from('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('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')
|
||||
})
|
||||
})
|
||||
|
||||
describe('returns error via cb 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))
|
||||
})
|
||||
|
||||
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()
|
||||
})
|
||||
})
|
||||
})
|
80
test/keys/secp256k1.spec.js
Normal file
80
test/keys/secp256k1.spec.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
const dirtyChai = require('dirty-chai')
|
||||
const expect = chai.expect
|
||||
chai.use(dirtyChai)
|
||||
const sinon = require('sinon')
|
||||
|
||||
const fixtures = require('../fixtures/secp256k1')
|
||||
const crypto = require('../../src')
|
||||
|
||||
describe('without libp2p-crypto-secp256k1 module present', () => {
|
||||
before(() => {
|
||||
sinon.replace(crypto.keys.supportedKeys, 'secp256k1', null)
|
||||
})
|
||||
|
||||
after(() => {
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('fails to generate a secp256k1 key', async () => {
|
||||
try {
|
||||
await crypto.keys.generateKeyPair('secp256k1', 256)
|
||||
} catch (err) {
|
||||
return // expected
|
||||
}
|
||||
throw new Error('Expected error to be thrown')
|
||||
})
|
||||
|
||||
it('fails to unmarshal a secp256k1 private key', async () => {
|
||||
try {
|
||||
await crypto.keys.unmarshalPrivateKey(fixtures.pbmPrivateKey)
|
||||
} catch (err) {
|
||||
return // expected
|
||||
}
|
||||
throw new Error('Expected error to be thrown')
|
||||
})
|
||||
|
||||
it('fails to unmarshal a secp256k1 public key', () => {
|
||||
expect(() => {
|
||||
crypto.keys.unmarshalPublicKey(fixtures.pbmPublicKey)
|
||||
}).to.throw(Error)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with libp2p-crypto-secp256k1 module present', () => {
|
||||
it('generates a valid key', async () => {
|
||||
const key = await crypto.keys.generateKeyPair('secp256k1', 256)
|
||||
expect(key).to.exist()
|
||||
})
|
||||
|
||||
it('protobuf encoding', async () => {
|
||||
const key = await crypto.keys.generateKeyPair('secp256k1', 256)
|
||||
expect(key).to.exist()
|
||||
|
||||
const keyMarshal = crypto.keys.marshalPrivateKey(key)
|
||||
const key2 = await crypto.keys.unmarshalPrivateKey(keyMarshal)
|
||||
const keyMarshal2 = crypto.keys.marshalPrivateKey(key2)
|
||||
|
||||
expect(keyMarshal).to.eql(keyMarshal2)
|
||||
|
||||
const pk = key.public
|
||||
const pkMarshal = crypto.keys.marshalPublicKey(pk)
|
||||
const pk2 = crypto.keys.unmarshalPublicKey(pkMarshal)
|
||||
const pkMarshal2 = crypto.keys.marshalPublicKey(pk2)
|
||||
|
||||
expect(pkMarshal).to.eql(pkMarshal2)
|
||||
})
|
||||
|
||||
it('unmarshals a secp256k1 private key', async () => {
|
||||
const key = await crypto.keys.unmarshalPrivateKey(fixtures.pbmPrivateKey)
|
||||
expect(key).to.exist()
|
||||
})
|
||||
|
||||
it('unmarshals a secp256k1 public key', () => {
|
||||
const key = crypto.keys.unmarshalPublicKey(fixtures.pbmPublicKey)
|
||||
expect(key).to.exist()
|
||||
})
|
||||
})
|
3
test/node.js
Normal file
3
test/node.js
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict'
|
||||
|
||||
require('./keys/rsa-crypto-libs')
|
129
test/rsa.spec.js
129
test/rsa.spec.js
@@ -1,129 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const expect = require('chai').expect
|
||||
|
||||
const crypto = require('../src')
|
||||
const rsa = crypto.keys.rsa
|
||||
|
||||
describe('RSA', () => {
|
||||
let key
|
||||
before(() => {
|
||||
key = crypto.generateKeyPair('RSA', 2048)
|
||||
})
|
||||
|
||||
it('generates a valid key', () => {
|
||||
expect(
|
||||
key
|
||||
).to.be.an.instanceof(
|
||||
rsa.RsaPrivateKey
|
||||
)
|
||||
|
||||
expect(
|
||||
key.hash()
|
||||
).to.have.length(
|
||||
34
|
||||
)
|
||||
})
|
||||
|
||||
it('signs', () => {
|
||||
const pk = key.public
|
||||
const text = key.genSecret()
|
||||
const sig = key.sign(text)
|
||||
|
||||
expect(
|
||||
pk.verify(text, sig)
|
||||
).to.be.eql(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('encoding', () => {
|
||||
const keyMarshal = key.marshal()
|
||||
const key2 = rsa.unmarshalRsaPrivateKey(keyMarshal)
|
||||
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
|
||||
)
|
||||
})
|
||||
|
||||
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', () => {
|
||||
const key2 = crypto.generateKeyPair('RSA', 2048)
|
||||
|
||||
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
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('sign and verify', () => {
|
||||
const data = new Buffer('hello world')
|
||||
const sig = key.sign(data)
|
||||
|
||||
expect(
|
||||
key.public.verify(data, sig)
|
||||
).to.be.eql(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('does fails to verify for different data', () => {
|
||||
const data = new Buffer('hello world')
|
||||
const sig = key.sign(data)
|
||||
|
||||
expect(
|
||||
key.public.verify(new Buffer('hello'), sig)
|
||||
).to.be.eql(
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
31
test/util.spec.js
Normal file
31
test/util.spec.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/* 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 util = require('../src/util')
|
||||
const BN = require('bn.js')
|
||||
|
||||
describe('Util', () => {
|
||||
let bn
|
||||
|
||||
before((done) => {
|
||||
bn = new BN('dead', 16)
|
||||
done()
|
||||
})
|
||||
|
||||
it('toBase64', (done) => {
|
||||
expect(util.toBase64(bn)).to.eql('3q0')
|
||||
done()
|
||||
})
|
||||
|
||||
it('toBase64 zero padding', (done) => {
|
||||
let bnpad = new BN('ff', 16)
|
||||
expect(util.toBase64(bnpad, 2)).to.eql('AP8')
|
||||
done()
|
||||
})
|
||||
})
|
29552
vendor/forge.bundle.js
vendored
29552
vendor/forge.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user