Compare commits

...

111 Commits

Author SHA1 Message Date
Jacob Heun
a05e870c45 chore: release version v0.19.2 2021-03-17 19:03:03 +01:00
Jacob Heun
bc681c76f4 chore: update contributors 2021-03-17 19:03:02 +01:00
Nadim Kobeissi
1c16dd3dec fix: ed25519 PeerID generation (#186)
* Fix Ed25519 PeerID generation

This commit pushes further fixes to the generation of Ed25519 peer IDs,
building upon the discussion in ipfs/js-ipfs#3591 and the subsequent
pull request libp2p/js-libp2p-crypto#185.

The purpose of this new pull request is to harmonize the encoding of
PeerIDs for Ed25519 keys such that the same new format is used
everywhere: peer IDs when assigned upon key generation, peer IDs when
shown via key listing, as well as the peer IDs displayed as IPNS names
when the key is used as the basis for an IPNS record.

Concretely, this changes the peer ID representation of Ed25519 keys from
the `Qm...` format to the newer `1...` format.

The accompanying test has been modified accordingly.

* Satisfy linter
2021-03-17 19:01:53 +01:00
Jacob Heun
4e5a05a12c chore: release version v0.19.1 2021-03-15 19:13:28 +01:00
Jacob Heun
c067685f45 chore: update contributors 2021-03-15 19:13:28 +01:00
Nadim Kobeissi
bc337698b6 fix: ed25519 key ID generation
As discussed here: https://github.com/ipfs/js-ipfs/issues/3591

Satisfy linter

test: actually verify ids
2021-03-15 19:02:31 +01:00
Jacob Heun
b07978dbea chore: release version v0.19.0 2021-01-15 14:50:47 +01:00
Jacob Heun
0cc270dc4a chore: update contributors 2021-01-15 14:50:46 +01:00
dependabot[bot]
b28c232e22 chore(deps): bump node-forge from 0.9.2 to 0.10.0 (#182)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 0.9.2 to 0.10.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/0.9.2...0.10.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-16 12:55:06 +01:00
Cayman
04a4e81317 chore: remove unused type (#183) 2020-12-16 12:53:22 +01:00
Jacob Heun
29df292338 chore: release version v0.18.0 2020-08-07 17:18:25 +02:00
Jacob Heun
253cca2799 chore: update contributors 2020-08-07 17:18:24 +02:00
Jacob Heun
afcffc8115 fix: remove rendundant public key (#181)
* fix: remove rendundant public key

BREAKING CHANGE: The private ed25519 key will no longer include the redundant public key

* chore: fix lint
2020-08-07 17:16:00 +02:00
Alex Potsides
a0f387aeab fix: replace node buffers with uint8arrays (#180)
* fix: replace node buffers with uint8arrays

All usage of node buffers have been replaced with uint8arrays.

BREAKING CHANGES:

- Where node Buffers were returned, now Uint8Arrays are

* chore: remove commented code
2020-08-07 16:23:02 +02:00
Jacob Heun
8b3dc56dc2 chore: release version v0.17.9 2020-08-05 17:18:44 +02:00
Jacob Heun
7888afada6 chore: update contributors 2020-08-05 17:18:43 +02:00
Jacob Heun
7273739f04 feat: add exporting/importing of non rsa keys in libp2p-key format (#179)
* feat: add exporting/importing of ed25519 keys in libp2p-key format

* feat: add libp2p-key export/import support for rsa and secp keys

* chore: dep bumps

* chore: update aegir

* refactor: import and export base64 strings

* refactor: simplify api for now

* chore: fix lint

* refactor: remove extraneous param

* refactor: clean up

* fix: review patches
2020-08-05 17:14:12 +02:00
Jacob Heun
609297be65 chore: release version v0.17.8 2020-07-20 15:23:49 +02:00
Jacob Heun
89a297793d chore: update contributors 2020-07-20 15:23:49 +02:00
Jacob Heun
32fae9b505 chore: fix lint 2020-07-20 15:13:46 +02:00
Jacob Heun
c2dd0a535d chore(types): fix typing 2020-07-20 15:13:46 +02:00
Jacob Heun
2f18a077b4 fix: go ed25519 interop
fixes https://github.com/libp2p/js-libp2p-crypto/issues/175
2020-07-20 15:13:46 +02:00
Jacob Heun
4aa77a6b12 chore: release version v0.17.7 2020-06-09 13:00:09 +02:00
Jacob Heun
210dd27479 chore: update contributors 2020-06-09 13:00:09 +02:00
Alex Potsides
437a76fbe3 chore: update node forge version
Use `^` so it's the same as libp2p
2020-06-09 12:57:27 +02:00
dependabot-preview[bot]
75d250c876 chore(deps-dev): bump aegir from 21.10.2 to 22.0.0 (#174)
Bumps [aegir](https://github.com/ipfs/aegir) from 21.10.2 to 22.0.0.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v21.10.2...v22.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-08 10:54:15 +02:00
Jacob Heun
e761427153 chore: release version v0.17.6 2020-04-07 16:15:48 +02:00
Jacob Heun
90d51ee8c7 chore: update contributors 2020-04-07 16:15:47 +02:00
Jacob Heun
ccda21fe91 Merge pull request #173 from ChainSafe/cayman/secp-migration
Integrate libp2p-crypto-secp256k1
2020-04-07 15:55:14 +02:00
Cayman
206999ce11 chore: fix secp256k1 references in readme 2020-04-06 15:44:36 -05:00
Cayman
3272688489 chore: integrate libp2p-crypto-secp256k1 2020-04-06 12:46:39 -05:00
Cayman
456a365378 Merge branch 'cayman/secp' into cayman/secp-migration 2020-04-06 11:56:27 -05:00
Cayman
42bd594068 chore: move files to secp256k1 directory 2020-04-06 11:55:35 -05:00
dependabot-preview[bot]
ab12e6f068 chore(deps-dev): bump @types/sinon from 7.5.2 to 9.0.0 (#172)
Bumps [@types/sinon](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sinon) from 7.5.2 to 9.0.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/sinon)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-04-01 16:47:39 +02:00
Jacob Heun
6bbf12c169 chore: release version v0.4.3 2020-03-25 12:59:04 +01:00
Jacob Heun
a68fc2e98d chore: update contributors 2020-03-25 12:59:03 +01:00
dependabot-preview[bot]
d73a0ca52e chore(deps): bump multibase from 0.6.1 to 0.7.0 (#26)
Bumps [multibase](https://github.com/multiformats/js-multibase) from 0.6.1 to 0.7.0.
- [Release notes](https://github.com/multiformats/js-multibase/releases)
- [Changelog](https://github.com/multiformats/js-multibase/blob/master/CHANGELOG.md)
- [Commits](https://github.com/multiformats/js-multibase/compare/v0.6.1...v0.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-25 12:55:12 +01:00
Jacob Heun
1b0fac84a8 chore: release version v0.17.5 2020-03-24 14:27:31 +01:00
Jacob Heun
efaafa9c06 chore: update contributors 2020-03-24 14:27:30 +01:00
dependabot-preview[bot]
88b3018c9c chore(deps): bump multibase from 0.6.1 to 0.7.0 (#171)
Bumps [multibase](https://github.com/multiformats/js-multibase) from 0.6.1 to 0.7.0.
- [Release notes](https://github.com/multiformats/js-multibase/releases)
- [Changelog](https://github.com/multiformats/js-multibase/blob/master/CHANGELOG.md)
- [Commits](https://github.com/multiformats/js-multibase/compare/v0.6.1...v0.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-24 14:11:07 +01:00
Jacob Heun
9aacb478c4 chore: release version v0.17.4 2020-03-23 17:06:35 +01:00
Jacob Heun
269d169f7c chore: update contributors 2020-03-23 17:06:35 +01:00
Hugo Dias
c956d1ad2a fix: add buffer, cleanup, reduce size (#170)
* fix: add buffer, cleanup, reduce size

- add buffer related to https://github.com/ipfs/js-ipfs/issues/2924
- remove unnecessary eslint ignore
- remove tweelnacl and use node-forge
- remove browserify-aes  and use node-forge
- use multibase to encode b58
- require only sha256 from multihashing
- reduce bundle size

after all the deps here https://github.com/ipfs/js-ipfs/issues/2924 are merged libp2p-crypto will be able to be bundle with `node: false` 🎉

* fix: reduce bundle size

* fix: use new secp

* fix: bundle size

* chore: update secp

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-03-23 16:55:35 +01:00
Jacob Heun
9b4231eb75 chore: release version v0.4.2 2020-03-17 12:11:28 +01:00
Jacob Heun
fdab19b7d9 chore: update contributors 2020-03-17 12:11:28 +01:00
Hugo Dias
35f196ea4d fix: add buffer and update deps (#25)
* fix: add buffer and update deps

update secp256k1 dep and fix code
use multibase to encode b58
avoid un-necessary circular dependency no libp2p-crypto
use  only sha256 from multihashing-async

* Update src/crypto.js

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: remove commitlint from CI

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-03-17 11:59:23 +01:00
Jacob Heun
d3601fa936 chore: release version v0.17.3 2020-02-26 17:21:45 +01:00
Jacob Heun
f01e3812e9 chore: update contributors 2020-02-26 17:21:45 +01:00
Alan Shaw
00477e3bcb perf: remove asn1.js and use node-forge (#166)
* perf: remove asn1.js from rsa

* fix: tweaks

* fix: it works, but I do not know 100% why

* chore: remove asn1.js

* fix: ensure jwk params encoded as uint

* fix: util tests

* fix: zero pad base64urlToBuffer

* fix: more zero pad

* test: add round trip test

* test: base64url to Buffer with padding
2020-02-26 17:16:32 +01:00
dependabot-preview[bot]
0f4c533dfa chore(deps-dev): bump sinon from 8.1.1 to 9.0.0
Bumps [sinon](https://github.com/sinonjs/sinon) from 8.1.1 to 9.0.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v8.1.1...v9.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-19 08:27:36 -05:00
dependabot-preview[bot]
d566e7ef3b chore(deps-dev): bump @types/mocha from 5.2.7 to 7.0.1
Bumps [@types/mocha](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mocha) from 5.2.7 to 7.0.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/mocha)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 08:31:56 -05:00
dependabot-preview[bot]
78e2ddd2bd chore(deps-dev): bump sinon from 7.5.0 to 8.1.1
Bumps [sinon](https://github.com/sinonjs/sinon) from 7.5.0 to 8.1.1.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v7.5.0...v8.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 08:31:41 -05:00
dependabot-preview[bot]
0ad513887a chore(deps): bump err-code from 1.1.2 to 2.0.0 (#165)
Bumps [err-code](https://github.com/IndigoUnited/js-err-code) from 1.1.2 to 2.0.0.
- [Release notes](https://github.com/IndigoUnited/js-err-code/releases)
- [Commits](https://github.com/IndigoUnited/js-err-code/compare/1.1.2...v2.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 07:57:07 -05:00
dependabot-preview[bot]
e7468d830d chore(deps-dev): bump aegir from 20.6.1 to 21.0.2 (#167)
Bumps [aegir](https://github.com/ipfs/aegir) from 20.6.1 to 21.0.2.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v20.6.1...v21.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 07:56:49 -05:00
dependabot-preview[bot]
ae109d46f7 chore(deps-dev): bump aegir from 20.6.1 to 21.0.2
Bumps [aegir](https://github.com/ipfs/aegir) from 20.6.1 to 21.0.2.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v20.6.1...v21.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 12:41:51 +01:00
dependabot-preview[bot]
41c9cd1691 chore(deps-dev): bump aegir from 19.0.5 to 20.6.0
Bumps [aegir](https://github.com/ipfs/aegir) from 19.0.5 to 20.6.0.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v19.0.5...v20.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-05 13:18:46 +01:00
dependabot-preview[bot]
3e88839c2b chore(deps-dev): bump libp2p-crypto from 0.16.3 to 0.17.2
Bumps [libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto) from 0.16.3 to 0.17.2.
- [Release notes](https://github.com/libp2p/js-libp2p-crypto/releases)
- [Changelog](https://github.com/libp2p/js-libp2p-crypto/blob/master/CHANGELOG.md)
- [Commits](https://github.com/libp2p/js-libp2p-crypto/compare/v0.16.3...v0.17.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-05 13:18:16 +01:00
Alan Shaw
cc2094975b perf: remove jwk2privPem and jwk2pubPem (#162)
These 2 unused functions required us to import the whole of the node-forge PKI implementation when we only use some RSA stuffs.

BREAKING CHANGE: removes unused jwk2pem methods `jwk2pubPem` and `jwk2privPem`. These methods are not being used in any js libp2p modules, so only users referencing these directly will be impacted.
2020-02-03 14:28:23 +01:00
Jacob Heun
ad4bf3b357 chore: release version v0.17.2 2020-01-17 12:08:41 +01:00
Jacob Heun
730d762717 chore: update contributors 2020-01-17 12:08:40 +01:00
Carson Farmer
e01977c5a3 feat: add typescript types + linting/tests (#161)
* feat: adds typescript types + linting/tests

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>

* feat: much better types testing

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>

* chore: revert eslintignore

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>

* feat: update types entry

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>

* chore: exclude has no effect here

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>

* feat: more nuanced return types on keypair

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>
2020-01-17 12:04:52 +01:00
Jacob Heun
89901f7097 chore: release version v0.4.1 2020-01-06 18:10:59 +01:00
Jacob Heun
9894c34f94 chore: update contributors 2020-01-06 18:10:49 +01:00
Alan Shaw
e36a9f6b79 chore: update multihashing-async dep (#19) 2020-01-06 10:07:09 -07:00
Jacob Heun
a521cd9b11 chore: release version v0.4.0 2019-07-10 11:45:02 +01:00
Jacob Heun
ed670209ad chore: update contributors 2019-07-10 11:45:02 +01:00
Alex Potsides
1974eb92be feat: use async await (#18)
BREAKING CHANGE: Callback support has been dropped in favor of async/await.

* feat: use async/await

This PR changes this module to remove callbacks and use async/await. The API is unchanged aside from the obvious removal of the `callback` parameter.

refs https://github.com/ipfs/js-ipfs/issues/1670

* fix: use latest multihashing-async as it is all promises now
2019-07-10 11:35:58 +01:00
Jacob Heun
fbd42385e3 chore: release version v0.3.1 2019-07-10 10:05:54 +01:00
Jacob Heun
9f01868c6c chore: update contributors 2019-07-10 10:05:53 +01:00
Arve Knudsen
3bb84514d1 fix(unmarshal): provide only one arg to callback (#17) 2019-07-10 09:56:11 +01:00
Vasco Santos
3f131d4a0a chore: add discourse badge (#15) 2019-04-18 19:30:06 +02:00
dignifiedquire
ce22cf13f0 chore: release version v0.3.0 2019-02-20 13:29:17 +01:00
dignifiedquire
5fc391c8e0 chore: update contributors 2019-02-20 13:29:17 +01:00
dignifiedquire
53a2b590a9 chore(dev-deps): update libp2p-crypto 2019-02-20 13:28:46 +01:00
Alberto Elias
f4dbd62e49 feat: add id() method to Secp256k1PrivateKey
Feature parity with ed25519 and rsa
2019-02-20 13:23:05 +01:00
David Dias
3a8bab9f44 chore: release version v0.2.3 2019-01-08 16:44:54 +01:00
David Dias
c983edfdb9 chore: update contributors 2019-01-08 16:44:54 +01:00
David Dias
6c9928abd6 chore: update deps 2019-01-08 16:43:36 +01:00
Hugo Dias
720246f012 chore: update deps 2019-01-08 16:42:39 +01:00
Hugo Dias
cfdcbe08d4 fix: update deps and repo setup 2019-01-08 16:42:39 +01:00
David Dias
1602c440ad chore: update deps 2018-06-04 09:48:43 +01:00
David Dias
937cc76714 add lead maintainer 2018-06-04 09:48:43 +01:00
ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ
651d08f67e Merge pull request #5 from libp2p/automatic-ci-script-update
Updating CI files
2017-12-22 15:00:13 +01:00
Victor Bjelkholm
f2b67f7d82 Updating CI files
This commit updates all CI scripts to the latest version
2017-12-22 14:16:17 +01:00
David Dias
98b285a840 chore: release version v0.2.2 2017-07-22 13:32:01 -07:00
David Dias
ce5fb8c1b9 chore: update contributors 2017-07-22 13:32:00 -07:00
David Dias
0dcf1a6f52 fix: circular circular dep -> DI 2017-07-22 13:31:42 -07:00
David Dias
8401154102 chore: update deps 2017-07-22 12:28:53 -07:00
David Dias
838ecdbaef chore: release version v0.2.1 2017-07-22 12:19:08 -07:00
David Dias
d14c11310e chore: update contributors 2017-07-22 12:19:08 -07:00
David Dias
41c03a86a5 chore: update deps 2017-07-22 11:40:00 -07:00
David Dias
1013becd66 chore: release version v0.2.0 2017-07-22 11:30:07 -07:00
David Dias
c21454c4e8 chore: update contributors 2017-07-22 11:30:07 -07:00
David Dias
4ee48a737a feat: next libp2p-crypto (#4)
* feat: next libp2p-crypto

* chore: update deps
2017-07-22 11:12:30 -07:00
David Dias
363cda56da chore: update ci 2017-07-21 11:38:33 -07:00
David Dias
d8b0c74ec9 chore: release version v0.1.4 2017-02-11 17:27:51 -08:00
David Dias
647fab7170 chore: update contributors 2017-02-11 17:27:51 -08:00
David Dias
e66383137f chore: add missing dependency 2017-02-11 17:27:29 -08:00
David Dias
638ea963e6 chore: release version v0.1.3 2017-02-10 18:36:19 -08:00
David Dias
35abf8fcb4 chore: update contributors 2017-02-10 18:36:19 -08:00
David Dias
9430e7f91e chore: update deps 2017-02-10 18:33:54 -08:00
David Dias
42678bba30 chore: release version v0.1.2 2017-02-09 14:08:25 -08:00
David Dias
f637ff2485 chore: update contributors 2017-02-09 14:08:25 -08:00
David Dias
4c2d42984d chore: release version v0.1.1 2017-02-09 08:05:13 -08:00
David Dias
de8b16b00b chore: update contributors 2017-02-09 08:05:13 -08:00
David Dias
73b8b39de5 chore: ^ to ~ 2017-02-09 08:03:23 -08:00
Friedel Ziegelmayer
288c9cff8f chore: release version v0.1.0 2017-02-09 12:43:44 +01:00
Friedel Ziegelmayer
418a0885ad chore: update contributors 2017-02-09 12:43:43 +01:00
Friedel Ziegelmayer
4c744d3b60 chore: update dependencies 2017-02-09 12:36:35 +01:00
Yusef Napora
4c36aeba17 feat: initial implementation 2017-02-09 12:35:39 +01:00
Friedel Ziegelmayer
e57e4ffa0d Initial commit 2017-01-19 17:50:23 +01:00
45 changed files with 1841 additions and 494 deletions

View File

@@ -1,3 +1,3 @@
module.exports = {
bundlesize: { maxSize: '155kB' }
bundlesize: { maxSize: '124kB' }
}

View File

@@ -1 +0,0 @@
src/keys/keys.proto.js

View File

@@ -1,3 +1,149 @@
<a name="0.19.2"></a>
## [0.19.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.19.1...v0.19.2) (2021-03-17)
### Bug Fixes
* ed25519 PeerID generation ([#186](https://github.com/libp2p/js-libp2p-crypto/issues/186)) ([1c16dd3](https://github.com/libp2p/js-libp2p-crypto/commit/1c16dd3)), closes [ipfs/js-ipfs#3591](https://github.com/ipfs/js-ipfs/issues/3591) [libp2p/js-libp2p-crypto#185](https://github.com/libp2p/js-libp2p-crypto/issues/185)
<a name="0.19.1"></a>
## [0.19.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.19.0...v0.19.1) (2021-03-15)
### Bug Fixes
* ed25519 key ID generation ([bc33769](https://github.com/libp2p/js-libp2p-crypto/commit/bc33769))
<a name="0.19.0"></a>
# [0.19.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.18.0...v0.19.0) (2021-01-15)
<a name="0.18.0"></a>
# [0.18.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.9...v0.18.0) (2020-08-07)
### Bug Fixes
* remove rendundant public key ([#181](https://github.com/libp2p/js-libp2p-crypto/issues/181)) ([afcffc8](https://github.com/libp2p/js-libp2p-crypto/commit/afcffc8))
* replace node buffers with uint8arrays ([#180](https://github.com/libp2p/js-libp2p-crypto/issues/180)) ([a0f387a](https://github.com/libp2p/js-libp2p-crypto/commit/a0f387a))
### BREAKING CHANGES
* The private ed25519 key will no longer include the redundant public key
* chore: fix lint
* - Where node Buffers were returned, now Uint8Arrays are
* chore: remove commented code
<a name="0.17.9"></a>
## [0.17.9](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.8...v0.17.9) (2020-08-05)
### Features
* add exporting/importing of non rsa keys in libp2p-key format ([#179](https://github.com/libp2p/js-libp2p-crypto/issues/179)) ([7273739](https://github.com/libp2p/js-libp2p-crypto/commit/7273739))
<a name="0.17.8"></a>
## [0.17.8](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.7...v0.17.8) (2020-07-20)
### Bug Fixes
* go ed25519 interop ([2f18a07](https://github.com/libp2p/js-libp2p-crypto/commit/2f18a07))
<a name="0.17.7"></a>
## [0.17.7](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.6...v0.17.7) (2020-06-09)
<a name="0.17.6"></a>
## [0.17.6](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.5...v0.17.6) (2020-04-07)
### Bug Fixes
* add buffer and update deps ([#25](https://github.com/libp2p/js-libp2p-crypto/issues/25)) ([35f196e](https://github.com/libp2p/js-libp2p-crypto/commit/35f196e))
* **unmarshal:** provide only one arg to callback ([#17](https://github.com/libp2p/js-libp2p-crypto/issues/17)) ([3bb8451](https://github.com/libp2p/js-libp2p-crypto/commit/3bb8451))
* circular circular dep -> DI ([0dcf1a6](https://github.com/libp2p/js-libp2p-crypto/commit/0dcf1a6))
* update deps and repo setup ([cfdcbe0](https://github.com/libp2p/js-libp2p-crypto/commit/cfdcbe0))
### Features
* add `id()` method to Secp256k1PrivateKey ([f4dbd62](https://github.com/libp2p/js-libp2p-crypto/commit/f4dbd62))
* initial implementation ([4c36aeb](https://github.com/libp2p/js-libp2p-crypto/commit/4c36aeb))
* next libp2p-crypto ([#4](https://github.com/libp2p/js-libp2p-crypto/issues/4)) ([4ee48a7](https://github.com/libp2p/js-libp2p-crypto/commit/4ee48a7))
* use async await ([#18](https://github.com/libp2p/js-libp2p-crypto/issues/18)) ([1974eb9](https://github.com/libp2p/js-libp2p-crypto/commit/1974eb9))
### BREAKING CHANGES
* Callback support has been dropped in favor of async/await.
* feat: use async/await
This PR changes this module to remove callbacks and use async/await. The API is unchanged aside from the obvious removal of the `callback` parameter.
refs https://github.com/ipfs/js-ipfs/issues/1670
* fix: use latest multihashing-async as it is all promises now
<a name="0.17.5"></a>
## [0.17.5](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.4...v0.17.5) (2020-03-24)
<a name="0.17.4"></a>
## [0.17.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.3...v0.17.4) (2020-03-23)
### Bug Fixes
* add buffer, cleanup, reduce size ([#170](https://github.com/libp2p/js-libp2p-crypto/issues/170)) ([c956d1a](https://github.com/libp2p/js-libp2p-crypto/commit/c956d1a))
<a name="0.17.3"></a>
## [0.17.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.2...v0.17.3) (2020-02-26)
### Performance Improvements
* remove asn1.js and use node-forge ([#166](https://github.com/libp2p/js-libp2p-crypto/issues/166)) ([00477e3](https://github.com/libp2p/js-libp2p-crypto/commit/00477e3))
* remove jwk2privPem and jwk2pubPem ([#162](https://github.com/libp2p/js-libp2p-crypto/issues/162)) ([cc20949](https://github.com/libp2p/js-libp2p-crypto/commit/cc20949))
### BREAKING CHANGES
* removes unused jwk2pem methods `jwk2pubPem` and `jwk2privPem`. These methods are not being used in any js libp2p modules, so only users referencing these directly will be impacted.
<a name="0.17.2"></a>
## [0.17.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.1...v0.17.2) (2020-01-17)
### Features
* add typescript types + linting/tests ([#161](https://github.com/libp2p/js-libp2p-crypto/issues/161)) ([e01977c](https://github.com/libp2p/js-libp2p-crypto/commit/e01977c))
<a name="0.17.1"></a>
## [0.17.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.17.0...v0.17.1) (2019-10-25)

122
README.md
View File

@@ -20,10 +20,12 @@ This repo contains the JavaScript implementation of the crypto primitives needed
## Table of Contents
- [js-libp2p-crypto](#js-libp2p-crypto)
- [Lead Maintainer](#Lead-Maintainer)
- [Table of Contents](#Table-of-Contents)
- [Install](#Install)
- [API](#API)
- [Lead Maintainer](#lead-maintainer)
- [Table of Contents](#table-of-contents)
- [Install](#install)
- [Usage](#usage)
- [Web Crypto API](#web-crypto-api)
- [API](#api)
- [`crypto.aes`](#cryptoaes)
- [`crypto.aes.create(key, iv)`](#cryptoaescreatekey-iv)
- [`decrypt(data)`](#decryptdata)
@@ -32,18 +34,19 @@ This repo contains the JavaScript implementation of the crypto primitives needed
- [`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)
- [`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(encryptedKey, password)`](#cryptokeysimportencryptedkey-password)
- [`privateKey.export(password, format)`](#privatekeyexportpassword-format)
- [`crypto.randomBytes(number)`](#cryptorandombytesnumber)
- [`crypto.pbkdf2(password, salt, iterations, keySize, hash)`](#cryptopbkdf2password-salt-iterations-keysize-hash)
- [Contribute](#contribute)
- [License](#license)
## Install
@@ -82,22 +85,22 @@ 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`.
- `key: Uint8Array` The key, if length `16` then `AES 128` is used. For length `32`, `AES 256` is used.
- `iv: Uint8Array` Must have length `16`.
Returns `Promise<{decrypt<Function>, encrypt<Function>}>`
##### `decrypt(data)`
- `data: Buffer`
- `data: Uint8Array`
Returns `Promise<Buffer>`
Returns `Promise<Uint8Array>`
##### `encrypt(data)`
- `data: Buffer`
- `data: Uint8Array`
Returns `Promise<Buffer>`
Returns `Promise<Uint8Array>`
```js
const crypto = require('libp2p-crypto')
@@ -105,26 +108,26 @@ const crypto = require('libp2p-crypto')
// 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])
const key128 = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
// A 16 bytes array, 128 Bits,
const IV = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
const IV = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
async function main () {
const decryptedMessage = 'Hello, world!'
// Encrypting
const cipher = await crypto.aes.create(key128, IV)
const encryptedBuffer = await cipher.encrypt(Buffer.from(decryptedMessage))
const encryptedBuffer = await cipher.encrypt(Uint8Array.from(decryptedMessage))
console.log(encryptedBuffer)
// prints: <Buffer 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
// prints: <Uint8Array 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
// Decrypting
const decipher = await crypto.aes.create(key128, IV)
const decryptedBuffer = await cipher.decrypt(encryptedBuffer)
console.log(decryptedBuffer)
// prints: <Buffer 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
// prints: <Uint8Array 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
console.log(decryptedBuffer.toString('utf-8'))
// prints: Hello, world!
@@ -140,15 +143,15 @@ Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as def
#### `crypto.hmac.create(hash, secret)`
- `hash: String`
- `secret: Buffer`
- `secret: Uint8Array`
Returns `Promise<{digest<Function>}>`
##### `digest(data)`
- `data: Buffer`
- `data: Uint8Array`
Returns `Promise<Buffer>`
Returns `Promise<Uint8Array>`
Example:
@@ -157,8 +160,8 @@ 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'))
const hmac = await crypto.hmac.create(hash, uint8ArrayFromString('secret'))
const sig = await hmac.digest(uint8ArrayFromString('hello world'))
console.log(sig)
}
@@ -171,16 +174,14 @@ main()
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.
Currently the `'RSA'`, `'ed25519'`, and `secp256k1` types are supported, although ed25519 and secp256k1 keys support only signing and verification of messages. For encryption / decryption support, RSA keys should be used.
### `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>}>`
Returns `Promise<{privateKey<Uint8Array>, publicKey<Uint8Array>}>`
Generates a keypair of the given type and bitsize.
@@ -198,7 +199,7 @@ Resolves to an object of the form:
```js
{
key: Buffer,
key: Uint8Array,
genSharedKey: Function
}
```
@@ -207,7 +208,7 @@ Resolves to an object of the form:
- `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'`
- `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512`
- `secret: Buffer`
- `secret: Uint8Array`
Returns `Promise`
@@ -218,30 +219,30 @@ Resolves to an object of the form:
```js
{
k1: {
iv: Buffer,
cipherKey: Buffer,
macKey: Buffer
iv: Uint8Array,
cipherKey: Uint8Array,
macKey: Uint8Array
},
k2: {
iv: Buffer,
cipherKey: Buffer,
macKey: Buffer
iv: Uint8Array,
cipherKey: Uint8Array,
macKey: Uint8Array
}
}
```
### `crypto.keys.marshalPublicKey(key, [type])`
- `key: keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | require('libp2p-crypto-secp256k1').Secp256k1PublicKey`
- `key: keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | keys.secp256k1.Secp256k1PublicKey`
- `type: String`, see [Supported Key Types](#supported-key-types) above. Defaults to 'rsa'.
Returns `Buffer`
Returns `Uint8Array`
Converts a public key object into a protobuf serialized public key.
### `crypto.keys.unmarshalPublicKey(buf)`
- `buf: Buffer`
- `buf: Uint8Array`
Returns `RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey`
@@ -249,37 +250,46 @@ Converts a protobuf serialized public key into its representative object.
### `crypto.keys.marshalPrivateKey(key, [type])`
- `key: keys.rsa.RsaPrivateKey | keys.ed25519.Ed25519PrivateKey | require('libp2p-crypto-secp256k1').Secp256k1PrivateKey`
- `key: keys.rsa.RsaPrivateKey | keys.ed25519.Ed25519PrivateKey | keys.secp256k1.Secp256k1PrivateKey`
- `type: String`, see [Supported Key Types](#supported-key-types) above.
Returns `Buffer`
Returns `Uint8Array`
Converts a private key object into a protobuf serialized private key.
### `crypto.keys.unmarshalPrivateKey(buf)`
- `buf: Buffer`
- `buf: Uint8Array`
Returns `Promise<RsaPrivateKey|Ed25519PrivateKey|Secp256k1PrivateKey>`
Converts a protobuf serialized private key into its representative object.
### `crypto.keys.import(pem, password)`
### `crypto.keys.import(encryptedKey, password)`
- `pem: string`
- `encryptedKey: string`
- `password: string`
Returns `Promise<RsaPrivateKey>`
Returns `Promise<PrivateKey>`
Converts a PEM password protected private key into its representative object.
Converts an exported private key into its representative object. Supported formats are 'pem' (RSA only) and 'libp2p-key'.
### `privateKey.export(password, format)`
- `password: string`
- `format: string` the format to export to: 'pem' (rsa only), 'libp2p-key'
Returns `string`
Exports the password protected `PrivateKey`. RSA keys will be exported as password protected PEM by default. Ed25519 and Secp256k1 keys will be exported as password protected AES-GCM base64 encoded strings ('libp2p-key' format).
### `crypto.randomBytes(number)`
- `number: Number`
Returns `Buffer`
Returns `Uint8Array`
Generates a Buffer with length `number` populated by random bytes.
Generates a Uint8Array with length `number` populated by random bytes.
### `crypto.pbkdf2(password, salt, iterations, keySize, hash)`

View File

@@ -1,13 +1,15 @@
{
"name": "libp2p-crypto",
"version": "0.17.1",
"version": "0.19.2",
"description": "Crypto primitives for libp2p",
"main": "src/index.js",
"types": "src/index.d.ts",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"browser": {
"./src/aes/ciphers.js": "./src/aes/ciphers-browser.js",
"./src/ciphers/aes-gcm.js": "./src/ciphers/aes-gcm.browser.js",
"./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": [
@@ -25,40 +27,44 @@
"release-minor": "aegir release --type minor",
"release-major": "aegir release --type major",
"coverage": "aegir coverage --ignore src/keys/keys.proto.js",
"size": "aegir build --bundlesize"
"size": "aegir build --bundlesize",
"test:types": "npx tsc"
},
"keywords": [
"IPFS",
"libp2p",
"crypto",
"rsa"
"rsa",
"secp256k1"
],
"license": "MIT",
"dependencies": {
"asmcrypto.js": "^2.3.2",
"asn1.js": "^5.2.0",
"bn.js": "^5.0.0",
"browserify-aes": "^1.2.0",
"bs58": "^4.0.1",
"err-code": "^1.1.2",
"err-code": "^2.0.0",
"is-typedarray": "^1.0.0",
"iso-random-stream": "^1.1.0",
"keypair": "^1.0.1",
"libp2p-crypto-secp256k1": "~0.4.0",
"multihashing-async": "~0.8.0",
"node-forge": "~0.9.1",
"multibase": "^3.0.0",
"multicodec": "^2.0.0",
"multihashes": "^4.0.2",
"multihashing-async": "^2.0.1",
"node-forge": "^0.10.0",
"pem-jwk": "^2.0.0",
"protons": "^1.0.1",
"rsa-pem-to-jwk": "^1.1.3",
"tweetnacl": "^1.0.1",
"ursa-optional": "~0.10.1"
"protons": "^2.0.0",
"secp256k1": "^4.0.0",
"uint8arrays": "^1.1.0",
"ursa-optional": "^0.10.1"
},
"devDependencies": {
"aegir": "^20.4.1",
"@types/chai": "^4.2.12",
"@types/chai-string": "^1.4.2",
"@types/dirty-chai": "^2.0.2",
"@types/mocha": "^8.0.1",
"aegir": "^25.0.0",
"benchmark": "^2.1.4",
"chai": "^4.2.0",
"chai-string": "^1.5.0",
"dirty-chai": "^2.0.1",
"sinon": "^7.5.0"
"sinon": "^9.0.0"
},
"engines": {
"node": ">=10.0.0",
@@ -73,28 +79,28 @@
},
"homepage": "https://github.com/libp2p/js-libp2p-crypto",
"contributors": [
"Alan Shaw <alan.shaw@protocol.ai>",
"Alan Shaw <alan@tableflip.io>",
"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>",
"dryajov <dryajov@gmail.com>",
"Alan Shaw <alan.shaw@protocol.ai>",
"Hugo Dias <hugomrdias@gmail.com>",
"Cayman <caymannava@gmail.com>",
"Yusef Napora <yusef@napora.org>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Arve Knudsen <arve.knudsen@gmail.com>",
"Alex Potsides <alex@achingbrain.net>",
"Vasco Santos <vasco.santos@ua.pt>",
"Alberto Elias <hi@albertoelias.me>",
"Jack Kleeman <jackkleeman@gmail.com>",
"Nadim Kobeissi <nadim@symbolic.software>",
"Richard Littauer <richard.littauer@gmail.com>",
"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>"
"nikuda <nikuda@gmail.com>",
"Joao Santos <jrmsantos15@gmail.com>",
"Carson Farmer <carson.farmer@gmail.com>",
"Tom Swindell <t.swindell@rubyx.co.uk>"
]
}

View File

@@ -1,8 +1,29 @@
'use strict'
const crypto = require('browserify-aes')
require('node-forge/lib/aes')
const forge = require('node-forge/lib/forge')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayFromString = require('uint8arrays/from-string')
module.exports = {
createCipheriv: crypto.createCipheriv,
createDecipheriv: crypto.createDecipheriv
createCipheriv: (mode, key, iv) => {
const cipher2 = forge.cipher.createCipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
return {
update: (data) => {
cipher2.update(forge.util.createBuffer(uint8ArrayToString(data, 'ascii')))
return uint8ArrayFromString(cipher2.output.getBytes(), 'ascii')
}
}
},
createDecipheriv: (mode, key, iv) => {
const cipher2 = forge.cipher.createDecipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
return {
update: (data) => {
cipher2.update(forge.util.createBuffer(uint8ArrayToString(data, 'ascii')))
return uint8ArrayFromString(cipher2.output.getBytes(), 'ascii')
}
}
}
}

View File

@@ -1,34 +0,0 @@
'use strict'
const asm = require('asmcrypto.js')
const validateCipherMode = require('./cipher-mode')
exports.create = async function (key, iv) { // eslint-disable-line require-await
// Throws an error if mode is invalid
validateCipherMode(key)
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
}

View File

@@ -0,0 +1,89 @@
'use strict'
const concat = require('uint8arrays/concat')
const fromString = require('uint8arrays/from-string')
const webcrypto = require('../webcrypto')
// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
/**
*
* @param {object} [options]
* @param {string} [options.algorithm=AES-GCM]
* @param {Number} [options.nonceLength=12]
* @param {Number} [options.keyLength=16]
* @param {string} [options.digest=sha256]
* @param {Number} [options.saltLength=16]
* @param {Number} [options.iterations=32767]
* @returns {*}
*/
function create ({
algorithm = 'AES-GCM',
nonceLength = 12,
keyLength = 16,
digest = 'SHA-256',
saltLength = 16,
iterations = 32767
} = {}) {
const crypto = webcrypto.get()
keyLength *= 8 // Browser crypto uses bits instead of bytes
/**
* Uses the provided password to derive a pbkdf2 key. The key
* will then be used to encrypt the data.
*
* @param {Uint8Array} data The data to decrypt
* @param {string} password A plain password
* @returns {Promise<Uint8Array>}
*/
async function encrypt (data, password) { // eslint-disable-line require-await
const salt = crypto.getRandomValues(new Uint8Array(saltLength))
const nonce = crypto.getRandomValues(new Uint8Array(nonceLength))
const aesGcm = { name: algorithm, iv: nonce }
// Derive a key using PBKDF2.
const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } }
const rawKey = await crypto.subtle.importKey('raw', fromString(password), { name: 'PBKDF2' }, false, ['deriveKey', 'deriveBits'])
const cryptoKey = await crypto.subtle.deriveKey(deriveParams, rawKey, { name: algorithm, length: keyLength }, true, ['encrypt'])
// Encrypt the string.
const ciphertext = await crypto.subtle.encrypt(aesGcm, cryptoKey, data)
return concat([salt, aesGcm.iv, new Uint8Array(ciphertext)])
}
/**
* Uses the provided password to derive a pbkdf2 key. The key
* will then be used to decrypt the data. The options used to create
* this decryption cipher must be the same as those used to create
* the encryption cipher.
*
* @param {Uint8Array} data The data to decrypt
* @param {string} password A plain password
* @returns {Promise<Uint8Array>}
*/
async function decrypt (data, password) {
const salt = data.slice(0, saltLength)
const nonce = data.slice(saltLength, saltLength + nonceLength)
const ciphertext = data.slice(saltLength + nonceLength)
const aesGcm = { name: algorithm, iv: nonce }
// Derive the key using PBKDF2.
const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } }
const rawKey = await crypto.subtle.importKey('raw', fromString(password), { name: 'PBKDF2' }, false, ['deriveKey', 'deriveBits'])
const cryptoKey = await crypto.subtle.deriveKey(deriveParams, rawKey, { name: algorithm, length: keyLength }, true, ['decrypt'])
// Decrypt the string.
const plaintext = await crypto.subtle.decrypt(aesGcm, cryptoKey, ciphertext)
return new Uint8Array(plaintext)
}
return {
encrypt,
decrypt
}
}
module.exports = {
create
}

130
src/ciphers/aes-gcm.js Normal file
View File

@@ -0,0 +1,130 @@
'use strict'
const crypto = require('crypto')
const uint8ArrayConcat = require('uint8arrays/concat')
const uint8ArrayFromString = require('uint8arrays/from-string')
// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
/**
*
* @param {object} [options]
* @param {Number} [options.algorithmTagLength=16]
* @param {Number} [options.nonceLength=12]
* @param {Number} [options.keyLength=16]
* @param {string} [options.digest=sha256]
* @param {Number} [options.saltLength=16]
* @param {Number} [options.iterations=32767]
* @returns {*}
*/
function create ({
algorithmTagLength = 16,
nonceLength = 12,
keyLength = 16,
digest = 'sha256',
saltLength = 16,
iterations = 32767
} = {}) {
const algorithm = 'aes-128-gcm'
/**
*
* @private
* @param {Uint8Array} data
* @param {Uint8Array} key
* @returns {Promise<Uint8Array>}
*/
async function encryptWithKey (data, key) { // eslint-disable-line require-await
const nonce = crypto.randomBytes(nonceLength)
// Create the cipher instance.
const cipher = crypto.createCipheriv(algorithm, key, nonce)
// Encrypt and prepend nonce.
const ciphertext = uint8ArrayConcat([cipher.update(data), cipher.final()])
return uint8ArrayConcat([nonce, ciphertext, cipher.getAuthTag()])
}
/**
* Uses the provided password to derive a pbkdf2 key. The key
* will then be used to encrypt the data.
*
* @param {Uint8Array} data The data to decrypt
* @param {string|Uint8Array} password A plain password
* @returns {Promise<Uint8Array>}
*/
async function encrypt (data, password) { // eslint-disable-line require-await
// Generate a 128-bit salt using a CSPRNG.
const salt = crypto.randomBytes(saltLength)
if (typeof password === 'string' || password instanceof String) {
password = uint8ArrayFromString(password)
}
// Derive a key using PBKDF2.
const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest)
// Encrypt and prepend salt.
return uint8ArrayConcat([salt, await encryptWithKey(Uint8Array.from(data), key)])
}
/**
* Decrypts the given cipher text with the provided key. The `key` should
* be a cryptographically safe key and not a plaintext password. To use
* a plaintext password, use `decrypt`. The options used to create
* this decryption cipher must be the same as those used to create
* the encryption cipher.
*
* @private
* @param {Uint8Array} ciphertextAndNonce The data to decrypt
* @param {Uint8Array} key
* @returns {Promise<Uint8Array>}
*/
async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await
// Create Uint8Arrays of nonce, ciphertext and tag.
const nonce = ciphertextAndNonce.slice(0, nonceLength)
const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength)
const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength)
// Create the cipher instance.
const cipher = crypto.createDecipheriv(algorithm, key, nonce)
// Decrypt and return result.
cipher.setAuthTag(tag)
return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()])
}
/**
* Uses the provided password to derive a pbkdf2 key. The key
* will then be used to decrypt the data. The options used to create
* this decryption cipher must be the same as those used to create
* the encryption cipher.
*
* @param {Uint8Array} data The data to decrypt
* @param {string|Uint8Array} password A plain password
*/
async function decrypt (data, password) { // eslint-disable-line require-await
// Create Uint8Arrays of salt and ciphertextAndNonce.
const salt = data.slice(0, saltLength)
const ciphertextAndNonce = data.slice(saltLength)
if (typeof password === 'string' || password instanceof String) {
password = uint8ArrayFromString(password)
}
// Derive the key using PBKDF2.
const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest)
// Decrypt and return result.
return decryptWithKey(ciphertextAndNonce, key)
}
return {
encrypt,
decrypt
}
}
module.exports = {
create
}

View File

@@ -10,7 +10,8 @@ const hashTypes = {
}
const sign = async (key, data) => {
return Buffer.from(await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data))
const buf = await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data)
return new Uint8Array(buf, buf.byteOffset, buf.byteLength)
}
exports.create = async function (hashType, secret) {

338
src/index.d.ts vendored Normal file
View File

@@ -0,0 +1,338 @@
/**
* Supported key types.
*/
export type KeyType = "Ed25519" | "RSA" | "secp256k1";
/**
* Maps an IPFS hash name to its node-forge equivalent.
* See https://github.com/multiformats/multihash/blob/master/hashtable.csv
*/
export type HashType = "SHA1" | "SHA256" | "SHA512";
/**
* Supported curve types.
*/
export type CurveType = "P-256" | "P-384" | "P-521";
/**
* Supported cipher types.
*/
export type CipherType = "AES-128" | "AES-256" | "Blowfish";
/**
* Exposes an interface to AES encryption (formerly Rijndael),
* as defined in U.S. Federal Information Processing Standards Publication 197.
* This uses CTR mode.
*/
export namespace aes {
/**
* AES Cipher in CTR mode.
*/
interface Cipher {
encrypt(data: Uint8Array): Promise<Uint8Array>;
decrypt(data: Uint8Array): Promise<Uint8Array>;
}
/**
* Create a new AES Cipher.
* @param key The key, if length 16 then AES 128 is used. For length 32, AES 256 is used.
* @param iv Must have length 16.
*/
function create(key: Uint8Array, iv: Uint8Array): Promise<Cipher>;
}
/**
* Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC)
* as defined in U.S. Federal Information Processing Standards Publication 198.
* An HMAC is a cryptographic hash that uses a key to sign a message.
* The receiver verifies the hash by recomputing it using the same key.
*/
export namespace hmac {
/**
* HMAC Digest.
*/
interface Digest {
digest(data: Uint8Array): Promise<Uint8Array>;
length: 20 | 32 | 64 | number;
}
/**
* Create a new HMAC Digest.
*/
function create(
hash: "SHA1" | "SHA256" | "SHA512" | string,
secret: Uint8Array
): Promise<Digest>;
}
/**
* Generic public key interface.
*/
export interface PublicKey {
readonly bytes: Uint8Array;
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
marshal(): Uint8Array;
equals(key: PublicKey): boolean;
hash(): Promise<Uint8Array>;
}
/**
* Generic private key interface.
*/
export interface PrivateKey {
readonly public: PublicKey;
readonly bytes: Uint8Array;
sign(data: Uint8Array): Promise<Uint8Array>;
marshal(): Uint8Array;
equals(key: PrivateKey): boolean;
hash(): Promise<Uint8Array>;
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*/
id(): Promise<string>;
/**
* Exports the password protected key in the format specified.
*/
export(password: string, format?: "pkcs-8" | string): Promise<string>;
}
export interface Keystretcher {
(res: Uint8Array): Keystretcher;
iv: Uint8Array;
cipherKey: Uint8Array;
macKey: Uint8Array;
}
export interface StretchPair {
k1: Keystretcher;
k2: Keystretcher;
}
/**
* Exposes an interface to various cryptographic key generation routines.
* Currently the 'RSA' and 'ed25519' types are supported, although ed25519 keys
* support only signing and verification of messages. For encryption / decryption
* support, RSA keys should be used.
* Installing the libp2p-crypto-secp256k1 module adds support for the 'secp256k1'
* type, which supports ECDSA signatures using the secp256k1 elliptic curve
* popularized by Bitcoin. This module is not installed by default, and should be
* explicitly depended on if your project requires secp256k1 support.
*/
export namespace keys {
export {};
export namespace supportedKeys {
namespace rsa {
class RsaPublicKey implements PublicKey {
constructor(key: Uint8Array);
readonly bytes: Uint8Array;
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
marshal(): Uint8Array;
encrypt(bytes: Uint8Array): Uint8Array;
equals(key: PublicKey): boolean;
hash(): Promise<Uint8Array>;
}
class RsaPrivateKey implements PrivateKey {
constructor(key: any, publicKey: Uint8Array);
readonly public: RsaPublicKey;
readonly bytes: Uint8Array;
genSecret(): Uint8Array;
sign(data: Uint8Array): Promise<Uint8Array>;
decrypt(bytes: Uint8Array): Uint8Array;
marshal(): Uint8Array;
equals(key: PrivateKey): boolean;
hash(): Promise<Uint8Array>;
id(): Promise<string>;
export(password: string, format?: string): Promise<string>;
}
function unmarshalRsaPublicKey(buf: Uint8Array): RsaPublicKey;
function unmarshalRsaPrivateKey(buf: Uint8Array): Promise<RsaPrivateKey>;
function generateKeyPair(bits: number): Promise<RsaPrivateKey>;
function fromJwk(jwk: Uint8Array): Promise<RsaPrivateKey>;
}
namespace ed25519 {
class Ed25519PublicKey implements PublicKey {
constructor(key: Uint8Array);
readonly bytes: Uint8Array;
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
marshal(): Uint8Array;
encrypt(bytes: Uint8Array): Uint8Array;
equals(key: PublicKey): boolean;
hash(): Promise<Uint8Array>;
}
class Ed25519PrivateKey implements PrivateKey {
constructor(key: Uint8Array, publicKey: Uint8Array);
readonly public: Ed25519PublicKey;
readonly bytes: Uint8Array;
sign(data: Uint8Array): Promise<Uint8Array>;
marshal(): Uint8Array;
equals(key: PrivateKey): boolean;
hash(): Promise<Uint8Array>;
id(): Promise<string>;
export(password: string, format?: string): Promise<string>;
}
function unmarshalEd25519PrivateKey(
buf: Uint8Array
): Promise<Ed25519PrivateKey>;
function unmarshalEd25519PublicKey(buf: Uint8Array): Ed25519PublicKey;
function generateKeyPair(): Promise<Ed25519PrivateKey>;
function generateKeyPairFromSeed(
seed: Uint8Array
): Promise<Ed25519PrivateKey>;
}
namespace secp256k1 {
class Secp256k1PublicKey implements PublicKey {
constructor(key: Uint8Array);
readonly bytes: Uint8Array;
verify(data: Uint8Array, sig: Uint8Array): Promise<boolean>;
marshal(): Uint8Array;
encrypt(bytes: Uint8Array): Uint8Array;
equals(key: PublicKey): boolean;
hash(): Promise<Uint8Array>;
}
class Secp256k1PrivateKey implements PrivateKey {
constructor(key: Uint8Array, publicKey: Uint8Array);
readonly public: Secp256k1PublicKey;
readonly bytes: Uint8Array;
sign(data: Uint8Array): Promise<Uint8Array>;
marshal(): Uint8Array;
equals(key: PrivateKey): boolean;
hash(): Promise<Uint8Array>;
id(): Promise<string>;
export(password: string, format?: string): Promise<string>;
}
function unmarshalSecp256k1PrivateKey(
bytes: Uint8Array
): Promise<Secp256k1PrivateKey>;
function unmarshalSecp256k1PublicKey(bytes: Uint8Array): Secp256k1PublicKey;
function generateKeyPair(): Promise<Secp256k1PrivateKey>;
}
}
export const keysPBM: any;
/**
* Generates a keypair of the given type and bitsize.
* @param type One of the supported key types.
* @param bits Number of bits. Minimum of 1024.
*/
export function generateKeyPair(
type: KeyType | string,
bits: number
): Promise<PrivateKey>;
export function generateKeyPair(
type: "Ed25519"
): Promise<keys.supportedKeys.ed25519.Ed25519PrivateKey>;
export function generateKeyPair(
type: "RSA",
bits: number
): Promise<keys.supportedKeys.rsa.RsaPrivateKey>;
export function generateKeyPair(
type: "secp256k1"
): Promise<keys.supportedKeys.secp256k1.Secp256k1PrivateKey>;
/**
* Generates a keypair of the given type and bitsize.
* @param type One of the supported key types. Currently only 'Ed25519' is supported.
* @param seed A 32 byte uint8array.
* @param bits Number of bits. Minimum of 1024.
*/
export function generateKeyPairFromSeed(
type: KeyType | string,
seed: Uint8Array,
bits: number
): Promise<PrivateKey>;
export function generateKeyPairFromSeed(
type: "Ed25519",
seed: Uint8Array,
bits: number
): Promise<keys.supportedKeys.ed25519.Ed25519PrivateKey>;
/**
* Generates an ephemeral public key and returns a function that will compute the shared secret key.
* Focuses only on ECDH now, but can be made more general in the future.
* @param curve The curve to use. One of 'P-256', 'P-384', 'P-521' is currently supported.
*/
export function generateEphemeralKeyPair(
curve: CurveType | string
): Promise<{
key: Uint8Array;
genSharedKey: (theirPub: Uint8Array, forcePrivate?: any) => Promise<Uint8Array>;
}>;
/**
* Generates a set of keys for each party by stretching the shared key.
* @param cipherType The cipher type to use. One of 'AES-128', 'AES-256', or 'Blowfish'
* @param hashType The hash type to use. One of 'SHA1', 'SHA2256', or 'SHA2512'.
* @param secret The shared key secret.
*/
export function keyStretcher(
cipherType: CipherType | string,
hashType: HashType | string,
secret: Uint8Array | string
): Promise<StretchPair>;
/**
* Converts a protobuf serialized public key into its representative object.
* @param buf The protobuf serialized public key.
*/
export function unmarshalPublicKey(buf: Uint8Array): PublicKey;
/**
* Converts a public key object into a protobuf serialized public key.
* @param key An RSA, Ed25519, or Secp256k1 public key object.
* @param type One of the supported key types.
*/
export function marshalPublicKey(key: PublicKey, type?: KeyType | string): Uint8Array;
/**
* Converts a protobuf serialized private key into its representative object.
* @param buf The protobuf serialized private key.
*/
export function unmarshalPrivateKey(buf: Uint8Array): Promise<PrivateKey>;
/**
* Converts a private key object into a protobuf serialized private key.
* @param key An RSA, Ed25519, or Secp256k1 private key object.
* @param type One of the supported key types.
*/
export function marshalPrivateKey(key: PrivateKey, type?: KeyType | string): Uint8Array;
/**
* Converts a PEM password protected private key into its representative object.
* @param pem Password protected private key in PEM format.
* @param password The password used to protect the key.
*/
function _import(pem: string, password: string, format?: string): Promise<supportedKeys.rsa.RsaPrivateKey>;
export { _import as import };
}
/**
* Generates a Uint8Array populated by random bytes.
* @param The size of the random bytes Uint8Array.
*/
export function randomBytes(number: number): Uint8Array;
/**
* Computes the Password-Based Key Derivation Function 2.
* @param password The password.
* @param salt The salt.
* @param iterations Number of iterations to use.
* @param keySize The size of the output key in bytes.
* @param hash The hash name ('sha1', 'sha2-512, ...)
*/
export function pbkdf2(
password: string | Uint8Array,
salt: string | Uint8Array,
iterations: number,
keySize: number,
hash: string
): Uint8Array;

View File

@@ -2,9 +2,11 @@
const errcode = require('err-code')
const webcrypto = require('../webcrypto')
const BN = require('asn1.js').bignum
const { toBase64, toBn } = require('../util')
const { base64urlToBuffer } = require('../util')
const validateCurveType = require('./validate-curve-type')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayConcat = require('uint8arrays/concat')
const uint8ArrayEquals = require('uint8arrays/equals')
const bits = {
'P-256': 256,
@@ -56,7 +58,7 @@ exports.generateEphmeralKeyPair = async function (curve) {
privateKey
]
return Buffer.from(await webcrypto.get().subtle.deriveBits(
const buffer = await webcrypto.get().subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
@@ -64,7 +66,9 @@ exports.generateEphmeralKeyPair = async function (curve) {
},
keys[1],
bits[curve]
))
)
return new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
}
const publicKey = await webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
@@ -87,10 +91,10 @@ const curveLengths = {
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)
return uint8ArrayConcat([
Uint8Array.from([4]), // uncompressed point
base64urlToBuffer(jwk.x, byteLen),
base64urlToBuffer(jwk.y, byteLen)
], 1 + byteLen * 2)
}
@@ -98,23 +102,20 @@ function marshalPublicKey (jwk) {
function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(Buffer.from([4]))) {
if (uint8ArrayEquals(!key.slice(0, 1), Uint8Array.from([4]))) {
throw errcode(new Error('Cannot unmarshal public key - invalid key format'), 'ERR_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),
x: uint8ArrayToString(key.slice(1, byteLen + 1), 'base64url'),
y: uint8ArrayToString(key.slice(1 + byteLen), 'base64url'),
ext: true
}
}
function unmarshalPrivateKey (curve, key) {
const result = unmarshalPublicKey(curve, key.public)
result.d = toBase64(new BN(key.private))
return result
}
const unmarshalPrivateKey = (curve, key) => ({
...unmarshalPublicKey(curve, key.public),
d: uint8ArrayToString(key.private, 'base64url')
})

View File

@@ -1,12 +1,13 @@
'use strict'
const multihashing = require('multihashing-async')
const sha = require('multihashing-async/src/sha')
const protobuf = require('protons')
const bs58 = require('bs58')
const errcode = require('err-code')
const uint8ArrayEquals = require('uint8arrays/equals')
const mh = require('multihashes')
const crypto = require('./ed25519')
const pbm = protobuf(require('./keys.proto'))
const exporter = require('./exporter')
class Ed25519PublicKey {
constructor (key) {
@@ -18,7 +19,7 @@ class Ed25519PublicKey {
}
marshal () {
return Buffer.from(this._key)
return this._key
}
get bytes () {
@@ -29,17 +30,17 @@ class Ed25519PublicKey {
}
equals (key) {
return this.bytes.equals(key.bytes)
return uint8ArrayEquals(this.bytes, key.bytes)
}
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
return sha.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
// key - 64 byte Uint8Array containing private key
// publicKey - 32 byte Uint8Array containing public key
constructor (key, publicKey) {
this._key = ensureKey(key, crypto.privateKeyLength)
this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
@@ -54,7 +55,7 @@ class Ed25519PrivateKey {
}
marshal () {
return Buffer.concat([Buffer.from(this._key), Buffer.from(this._publicKey)])
return this._key
}
get bytes () {
@@ -65,11 +66,11 @@ class Ed25519PrivateKey {
}
equals (key) {
return this.bytes.equals(key.bytes)
return uint8ArrayEquals(this.bytes, key.bytes)
}
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
return sha.multihashing(this.bytes, 'sha2-256')
}
/**
@@ -82,15 +83,38 @@ class Ed25519PrivateKey {
* @returns {Promise<String>}
*/
async id () {
const hash = await this.public.hash()
return bs58.encode(hash)
const encoding = mh.encode(this.public.bytes, 'identity')
return await mh.toB58String(encoding)
}
/**
* Exports the key into a password protected `format`
*
* @param {string} password - The password to encrypt the key
* @param {string} [format=libp2p-key] - The format in which to export as
* @returns {Promise<Uint8Array>} The encrypted private key
*/
async export (password, format = 'libp2p-key') { // eslint-disable-line require-await
if (format === 'libp2p-key') {
return exporter.export(this.bytes, password)
} else {
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
}
}
}
function unmarshalEd25519PrivateKey (bytes) {
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
// Try the old, redundant public key version
if (bytes.length > crypto.privateKeyLength) {
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
}
bytes = ensureKey(bytes, crypto.privateKeyLength)
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
const publicKeyBytes = bytes.slice(crypto.publicKeyLength)
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
}
@@ -100,21 +124,19 @@ function unmarshalEd25519PublicKey (bytes) {
}
async function generateKeyPair () {
const { secretKey, publicKey } = await crypto.generateKey()
return new Ed25519PrivateKey(secretKey, publicKey)
const { privateKey, publicKey } = await crypto.generateKey()
return new Ed25519PrivateKey(privateKey, publicKey)
}
async function generateKeyPairFromSeed (seed) {
const { secretKey, publicKey } = await crypto.generateKeyFromSeed(seed)
return new Ed25519PrivateKey(secretKey, publicKey)
const { privateKey, publicKey } = await crypto.generateKeyFromSeed(seed)
return new Ed25519PrivateKey(privateKey, publicKey)
}
function ensureKey (key, length) {
if (Buffer.isBuffer(key)) {
key = new Uint8Array(key)
}
if (!(key instanceof Uint8Array) || key.length !== length) {
throw errcode(new Error('Key must be a Uint8Array or Buffer of length ' + length), 'ERR_INVALID_KEY_TYPE')
key = Uint8Array.from(key || [])
if (key.length !== length) {
throw errcode(new Error(`Key must be a Uint8Array of length ${length}, got ${key.length}`), 'ERR_INVALID_KEY_TYPE')
}
return key
}

View File

@@ -1,23 +1,24 @@
'use strict'
const nacl = require('tweetnacl')
exports.publicKeyLength = nacl.sign.publicKeyLength
exports.privateKeyLength = nacl.sign.secretKeyLength
require('node-forge/lib/ed25519')
const forge = require('node-forge/lib/forge')
exports.publicKeyLength = forge.pki.ed25519.constants.PUBLIC_KEY_BYTE_LENGTH
exports.privateKeyLength = forge.pki.ed25519.constants.PRIVATE_KEY_BYTE_LENGTH
exports.generateKey = async function () { // eslint-disable-line require-await
return nacl.sign.keyPair()
return forge.pki.ed25519.generateKeyPair()
}
// seed should be a 32 byte uint8array
exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line require-await
return nacl.sign.keyPair.fromSeed(seed)
return forge.pki.ed25519.generateKeyPair({ seed })
}
exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
return Buffer.from(nacl.sign.detached(msg, key))
return forge.pki.ed25519.sign({ message: msg, privateKey: key })
// return Uint8Array.from(nacl.sign.detached(msg, key))
}
exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await
return nacl.sign.detached.verify(msg, sig, key)
return forge.pki.ed25519.verify({ signature: sig, message: msg, publicKey: key })
}

22
src/keys/exporter.js Normal file
View File

@@ -0,0 +1,22 @@
'use strict'
const multibase = require('multibase')
const ciphers = require('../ciphers/aes-gcm')
module.exports = {
/**
* Exports the given PrivateKey as a base64 encoded string.
* The PrivateKey is encrypted via a password derived PBKDF2 key
* leveraging the aes-gcm cipher algorithm.
*
* @param {Uint8Array} privateKey The PrivateKey protobuf
* @param {string} password
* @returns {Promise<string>} A base64 encoded string
*/
export: async function (privateKey, password) {
const cipher = ciphers.create()
const encryptedKey = await cipher.encrypt(privateKey, password)
const base64 = multibase.names.base64
return base64.encode(encryptedKey)
}
}

22
src/keys/importer.js Normal file
View File

@@ -0,0 +1,22 @@
'use strict'
const multibase = require('multibase')
const ciphers = require('../ciphers/aes-gcm')
module.exports = {
/**
* Attempts to decrypt a base64 encoded PrivateKey string
* with the given password. The privateKey must have been exported
* using the same password and underlying cipher (aes-gcm)
*
* @param {string} privateKey A base64 encoded encrypted key
* @param {string} password
* @returns {Promise<Uint8Array>} The private key protobuf
*/
import: async function (privateKey, password) {
const base64 = multibase.names.base64
const encryptedKey = base64.decode(privateKey)
const cipher = ciphers.create()
return await cipher.decrypt(encryptedKey, password)
}
}

View File

@@ -3,17 +3,19 @@
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')
const errcode = require('err-code')
const uint8ArrayFromString = require('uint8arrays/from-string')
const importer = require('./importer')
exports = module.exports
const supportedKeys = {
rsa: require('./rsa-class'),
ed25519: require('./ed25519-class'),
secp256k1: require('libp2p-crypto-secp256k1')(keysPBM, require('../random-bytes'))
secp256k1: require('./secp256k1-class')(keysPBM, require('../random-bytes'))
}
exports.supportedKeys = supportedKeys
@@ -109,12 +111,25 @@ exports.marshalPrivateKey = (key, type) => {
return key.bytes
}
exports.import = async (pem, password) => { // eslint-disable-line require-await
const key = forge.pki.decryptRsaPrivateKey(pem, password)
/**
*
* @param {string} encryptedKey
* @param {string} password
*/
exports.import = async (encryptedKey, password) => { // eslint-disable-line require-await
try {
const key = await importer.import(encryptedKey, password)
return exports.unmarshalPrivateKey(key)
} catch (_) {
// Ignore and try the old pem decrypt
}
// Only rsa supports pem right now
const key = forge.pki.decryptRsaPrivateKey(encryptedKey, password)
if (key === null) {
throw errcode(new Error('Cannot read the key, most likely the password is wrong or not a RSA key'), 'ERR_CANNOT_DECRYPT_PEM')
}
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
der = Buffer.from(der.getBytes(), 'binary')
der = uint8ArrayFromString(der.getBytes(), 'ascii')
return supportedKeys.rsa.unmarshalRsaPrivateKey(der)
}

View File

@@ -1,18 +1,8 @@
'use strict'
const forge = {
util: require('node-forge/lib/util'),
pki: require('node-forge/lib/pki'),
jsbn: require('node-forge/lib/jsbn')
}
function base64urlToBigInteger (str) {
var bytes = forge.util.decode64(
(str + '==='.slice((str.length + 3) % 4))
.replace(/-/g, '+')
.replace(/_/g, '/'))
return new forge.jsbn.BigInteger(forge.util.bytesToHex(bytes), 16)
}
require('node-forge/lib/rsa')
const forge = require('node-forge/lib/forge')
const { base64urlToBigInteger } = require('../util')
function convert (key, types) {
return types.map(t => base64urlToBigInteger(key[t]))
@@ -22,21 +12,11 @@ function jwk2priv (key) {
return forge.pki.setRsaPrivateKey(...convert(key, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']))
}
function jwk2privPem (key) {
return forge.pki.privateKeyToPem(jwk2priv(key))
}
function jwk2pub (key) {
return forge.pki.setRsaPublicKey(...convert(key, ['n', 'e']))
}
function jwk2pubPem (key) {
return forge.pki.publicKeyToPem(jwk2pub(key))
}
module.exports = {
jwk2pub,
jwk2pubPem,
jwk2priv,
jwk2privPem
jwk2priv
}

View File

@@ -1,6 +1,8 @@
'use strict'
const errcode = require('err-code')
const uint8ArrayConcat = require('uint8arrays/concat')
const uint8ArrayFromString = require('uint8arrays/from-string')
const hmac = require('../hmac')
const cipherMap = {
@@ -35,7 +37,7 @@ module.exports = async (cipherType, hash, secret) => {
const cipherKeySize = cipher.keySize
const ivSize = cipher.ivSize
const hmacKeySize = 20
const seed = Buffer.from('key expansion')
const seed = uint8ArrayFromString('key expansion')
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
const m = await hmac.create(hash, secret)
@@ -45,7 +47,7 @@ module.exports = async (cipherType, hash, secret) => {
let j = 0
while (j < resultLength) {
const b = await m.digest(Buffer.concat([a, seed]))
const b = await m.digest(uint8ArrayConcat([a, seed]))
let todo = b.length
if (j + todo > resultLength) {
@@ -58,7 +60,7 @@ module.exports = async (cipherType, hash, secret) => {
}
const half = resultLength / 2
const resultBuffer = Buffer.concat(result)
const resultBuffer = uint8ArrayConcat(result)
const r1 = resultBuffer.slice(0, half)
const r2 = resultBuffer.slice(half, resultLength)

View File

@@ -2,6 +2,8 @@
const webcrypto = require('../webcrypto')
const randomBytes = require('../random-bytes')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayFromString = require('uint8arrays/from-string')
exports.utils = require('./rsa-utils')
@@ -74,7 +76,7 @@ exports.hashAndSign = async function (key, msg) {
Uint8Array.from(msg)
)
return Buffer.from(sig)
return new Uint8Array(sig, sig.byteOffset, sig.byteLength)
}
exports.hashAndVerify = async function (key, sig, msg) {
@@ -128,8 +130,8 @@ RSA encryption/decryption for the browser with webcrypto workarround
Explanation:
- Convert JWK to nodeForge
- Convert msg buffer to nodeForge buffer: ByteBuffer is a "binary-string backed buffer", so let's make our buffer a binary string
- Convert resulting nodeForge buffer to buffer: it returns a binary string, turn that into a uint8array(buffer)
- Convert msg Uint8Array to nodeForge buffer: ByteBuffer is a "binary-string backed buffer", so let's make our Uint8Array a binary string
- Convert resulting nodeForge buffer to Uint8Array: it returns a binary string, turn that into a Uint8Array
*/
@@ -137,9 +139,9 @@ const { jwk2pub, jwk2priv } = require('./jwk2pem')
function convertKey (key, pub, msg, handle) {
const fkey = pub ? jwk2pub(key) : jwk2priv(key)
const fmsg = Buffer.from(msg).toString('binary')
const fmsg = uint8ArrayToString(Uint8Array.from(msg), 'ascii')
const fomsg = handle(fmsg, fkey)
return Buffer.from(fomsg, 'binary')
return uint8ArrayFromString(fomsg, 'ascii')
}
exports.encrypt = function (key, msg) {

View File

@@ -1,15 +1,18 @@
'use strict'
const multihashing = require('multihashing-async')
const sha = require('multihashing-async/src/sha')
const protobuf = require('protons')
const bs58 = require('bs58')
const errcode = require('err-code')
const uint8ArrayEquals = require('uint8arrays/equals')
const uint8ArrayToString = require('uint8arrays/to-string')
require('node-forge/lib/sha512')
require('node-forge/lib/ed25519')
const forge = require('node-forge/lib/forge')
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
require('node-forge/lib/sha512')
require('node-forge/lib/pbe')
const forge = require('node-forge/lib/forge')
const exporter = require('./exporter')
class RsaPublicKey {
constructor (key) {
@@ -36,17 +39,17 @@ class RsaPublicKey {
}
equals (key) {
return this.bytes.equals(key.bytes)
return uint8ArrayEquals(this.bytes, key.bytes)
}
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
return sha.multihashing(this.bytes, 'sha2-256')
}
}
class RsaPrivateKey {
// key - Object of the jwk format
// publicKey - Buffer of the spki format
// publicKey - Uint8Array of the spki format
constructor (key, publicKey) {
this._key = key
this._publicKey = publicKey
@@ -84,11 +87,11 @@ class RsaPrivateKey {
}
equals (key) {
return this.bytes.equals(key.bytes)
return uint8ArrayEquals(this.bytes, key.bytes)
}
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
return sha.multihashing(this.bytes, 'sha2-256')
}
/**
@@ -102,36 +105,33 @@ class RsaPrivateKey {
*/
async id () {
const hash = await this.public.hash()
return bs58.encode(hash)
return uint8ArrayToString(hash, 'base58btc')
}
/**
* Exports the key into a password protected PEM format
*
* @param {string} password - The password to read the encrypted PEM
* @param {string} [format] - Defaults to 'pkcs-8'.
* @returns {KeyInfo}
* @param {string} [format=pkcs-8] - The format in which to export as
*/
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 buffer = new forge.util.ByteBuffer(this.marshal())
const asn1 = forge.asn1.fromDer(buffer)
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
const options = {
algorithm: 'aes256',
count: 10000,
saltSize: 128 / 8,
prfAlgorithm: 'sha512'
}
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
return forge.pki.encryptRsaPrivateKey(privateKey, password, options)
} else if (format === 'libp2p-key') {
return exporter.export(this.bytes, password)
} else {
throw errcode(new Error(`Unknown export format '${format}'. Must be pkcs-8`), 'ERR_INVALID_EXPORT_FORMAT')
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
}
return pem
}
}

View File

@@ -1,68 +1,28 @@
'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()
)
})
require('node-forge/lib/asn1')
require('node-forge/lib/rsa')
const forge = require('node-forge/lib/forge')
const { bigIntegerToUintBase64url, base64urlToBigInteger } = require('./../util')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string')
// Convert a PKCS#1 in ASN1 DER format to a JWK key
exports.pkcs1ToJwk = function (bytes) {
const asn1 = RSAPrivateKey.decode(bytes, 'der')
const asn1 = forge.asn1.fromDer(uint8ArrayToString(bytes, 'ascii'))
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
// https://tools.ietf.org/html/rfc7518#section-6.3.1
return {
kty: 'RSA',
n: 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),
n: bigIntegerToUintBase64url(privateKey.n),
e: bigIntegerToUintBase64url(privateKey.e),
d: bigIntegerToUintBase64url(privateKey.d),
p: bigIntegerToUintBase64url(privateKey.p),
q: bigIntegerToUintBase64url(privateKey.q),
dp: bigIntegerToUintBase64url(privateKey.dP),
dq: bigIntegerToUintBase64url(privateKey.dQ),
qi: bigIntegerToUintBase64url(privateKey.qInv),
alg: 'RS256',
kid: '2011-04-29'
}
@@ -70,28 +30,29 @@ exports.pkcs1ToJwk = function (bytes) {
// 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')
const asn1 = forge.pki.privateKeyToAsn1({
n: base64urlToBigInteger(jwk.n),
e: base64urlToBigInteger(jwk.e),
d: base64urlToBigInteger(jwk.d),
p: base64urlToBigInteger(jwk.p),
q: base64urlToBigInteger(jwk.q),
dP: base64urlToBigInteger(jwk.dp),
dQ: base64urlToBigInteger(jwk.dq),
qInv: base64urlToBigInteger(jwk.qi)
})
return uint8ArrayFromString(forge.asn1.toDer(asn1).getBytes(), 'ascii')
}
// Convert a PKCIX in ASN1 DER format to a JWK key
exports.pkixToJwk = function (bytes) {
const ndata = PublicKey.decode(bytes, 'der')
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
const asn1 = forge.asn1.fromDer(uint8ArrayToString(bytes, 'ascii'))
const publicKey = forge.pki.publicKeyFromAsn1(asn1)
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
n: bigIntegerToUintBase64url(publicKey.n),
e: bigIntegerToUintBase64url(publicKey.e),
alg: 'RS256',
kid: '2011-04-29'
}
@@ -99,16 +60,10 @@ exports.pkixToJwk = function (bytes) {
// 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')
const asn1 = forge.pki.publicKeyToAsn1({
n: base64urlToBigInteger(jwk.n),
e: base64urlToBigInteger(jwk.e)
})
return uint8ArrayFromString(forge.asn1.toDer(asn1).getBytes(), 'ascii')
}

View File

@@ -3,7 +3,10 @@
const crypto = require('crypto')
const errcode = require('err-code')
const randomBytes = require('../random-bytes')
// @ts-check
/**
* @type {PrivateKey}
*/
let keypair
try {
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'keypair') {

128
src/keys/secp256k1-class.js Normal file
View File

@@ -0,0 +1,128 @@
'use strict'
const sha = require('multihashing-async/src/sha')
const errcode = require('err-code')
const uint8ArrayEquals = require('uint8arrays/equals')
const uint8ArrayToString = require('uint8arrays/to-string')
const exporter = require('./exporter')
module.exports = (keysProtobuf, randomBytes, crypto) => {
crypto = crypto || require('./secp256k1')(randomBytes)
class Secp256k1PublicKey {
constructor (key) {
crypto.validatePublicKey(key)
this._key = key
}
verify (data, sig) {
return crypto.hashAndVerify(this._key, sig, data)
}
marshal () {
return crypto.compressPublicKey(this._key)
}
get bytes () {
return keysProtobuf.PublicKey.encode({
Type: keysProtobuf.KeyType.Secp256k1,
Data: this.marshal()
})
}
equals (key) {
return uint8ArrayEquals(this.bytes, key.bytes)
}
hash () {
return sha.multihashing(this.bytes, 'sha2-256')
}
}
class Secp256k1PrivateKey {
constructor (key, publicKey) {
this._key = key
this._publicKey = publicKey || crypto.computePublicKey(key)
crypto.validatePrivateKey(this._key)
crypto.validatePublicKey(this._publicKey)
}
sign (message) {
return crypto.hashAndSign(this._key, message)
}
get public () {
return new Secp256k1PublicKey(this._publicKey)
}
marshal () {
return this._key
}
get bytes () {
return keysProtobuf.PrivateKey.encode({
Type: keysProtobuf.KeyType.Secp256k1,
Data: this.marshal()
})
}
equals (key) {
return uint8ArrayEquals(this.bytes, key.bytes)
}
hash () {
return sha.multihashing(this.bytes, 'sha2-256')
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @returns {Promise<string>}
*/
async id () {
const hash = await this.public.hash()
return uint8ArrayToString(hash, 'base58btc')
}
/**
* Exports the key into a password protected `format`
*
* @param {string} password - The password to encrypt the key
* @param {string} [format=libp2p-key] - The format in which to export as
* @returns {Promise<string>} The encrypted private key
*/
async export (password, format = 'libp2p-key') { // eslint-disable-line require-await
if (format === 'libp2p-key') {
return exporter.export(this.bytes, password)
} else {
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
}
}
}
function unmarshalSecp256k1PrivateKey (bytes) {
return new Secp256k1PrivateKey(bytes)
}
function unmarshalSecp256k1PublicKey (bytes) {
return new Secp256k1PublicKey(bytes)
}
async function generateKeyPair () {
const privateKeyBytes = await crypto.generateKey()
return new Secp256k1PrivateKey(privateKeyBytes)
}
return {
Secp256k1PublicKey,
Secp256k1PrivateKey,
unmarshalSecp256k1PrivateKey,
unmarshalSecp256k1PublicKey,
generateKeyPair
}
}

69
src/keys/secp256k1.js Normal file
View File

@@ -0,0 +1,69 @@
'use strict'
const secp256k1 = require('secp256k1')
const sha = require('multihashing-async/src/sha')
const HASH_ALGORITHM = 'sha2-256'
module.exports = (randomBytes) => {
const privateKeyLength = 32
function generateKey () {
let privateKey
do {
privateKey = randomBytes(32)
} while (!secp256k1.privateKeyVerify(privateKey))
return privateKey
}
async function hashAndSign (key, msg) {
const digest = await sha.digest(msg, HASH_ALGORITHM)
const sig = secp256k1.ecdsaSign(digest, key)
return secp256k1.signatureExport(sig.signature)
}
async function hashAndVerify (key, sig, msg) {
const digest = await sha.digest(msg, HASH_ALGORITHM)
sig = secp256k1.signatureImport(sig)
return secp256k1.ecdsaVerify(sig, digest, key)
}
function compressPublicKey (key) {
if (!secp256k1.publicKeyVerify(key)) {
throw new Error('Invalid public key')
}
return secp256k1.publicKeyConvert(key, true)
}
function decompressPublicKey (key) {
return secp256k1.publicKeyConvert(key, false)
}
function validatePrivateKey (key) {
if (!secp256k1.privateKeyVerify(key)) {
throw new Error('Invalid private key')
}
}
function validatePublicKey (key) {
if (!secp256k1.publicKeyVerify(key)) {
throw new Error('Invalid public key')
}
}
function computePublicKey (privateKey) {
validatePrivateKey(privateKey)
return secp256k1.publicKeyCreate(privateKey)
}
return {
generateKey,
privateKeyLength,
hashAndSign,
hashAndVerify,
compressPublicKey,
decompressPublicKey,
validatePrivateKey,
validatePublicKey,
computePublicKey
}
}

View File

@@ -1,20 +1,43 @@
'use strict'
const BN = require('asn1.js').bignum
require('node-forge/lib/util')
require('node-forge/lib/jsbn')
const forge = require('node-forge/lib/forge')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayConcat = require('uint8arrays/concat')
// 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
const s = bn.toArrayLike(Buffer, 'be', len).toString('base64')
exports.bigIntegerToUintBase64url = (num, len) => {
// Call `.abs()` to convert to unsigned
let buf = Uint8Array.from(num.abs().toByteArray()) // toByteArray converts to big endian
return s
.replace(/(=*)$/, '') // Remove any trailing '='s
.replace(/\+/g, '-') // 62nd char of encoding
.replace(/\//g, '_') // 63rd char of encoding
// toByteArray() gives us back a signed array, which will include a leading 0
// byte if the most significant bit of the number is 1:
// https://docs.microsoft.com/en-us/windows/win32/seccertenroll/about-integer
// Our number will always be positive so we should remove the leading padding.
buf = buf[0] === 0 ? buf.slice(1) : buf
if (len != null) {
if (buf.length > len) throw new Error('byte array longer than desired length')
buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf])
}
return uint8ArrayToString(buf, 'base64url')
}
// Convert a base64 encoded string to a BN.js instance
exports.toBn = function toBn (str) {
return new BN(Buffer.from(str, 'base64'))
// Convert a base64url encoded string to a BigInteger
exports.base64urlToBigInteger = str => {
const buf = exports.base64urlToBuffer(str)
return new forge.jsbn.BigInteger(uint8ArrayToString(buf, 'base16'), 16)
}
exports.base64urlToBuffer = (str, len) => {
let buf = uint8ArrayFromString(str, 'base64urlpad')
if (len != null) {
if (buf.length > len) throw new Error('byte array longer than desired length')
buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf])
}
return buf
}

View File

@@ -1,4 +1,5 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-disable valid-jsdoc */
/* eslint-env mocha */
'use strict'
@@ -17,13 +18,15 @@ const bytes = {
32: 'AES-256'
}
/** @typedef {import("libp2p-crypto").aes.Cipher} Cipher */
describe('AES-CTR', () => {
Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - encrypt and decrypt`, async () => {
const key = Buffer.alloc(parseInt(byte, 10))
const key = new Uint8Array(parseInt(byte, 10))
key.fill(5)
const iv = Buffer.alloc(16)
const iv = new Uint8Array(16)
iv.fill(1)
const cipher = await crypto.aes.create(key, iv)
@@ -38,18 +41,18 @@ describe('AES-CTR', () => {
Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - fixed - encrypt and decrypt`, async () => {
const key = Buffer.alloc(parseInt(byte, 10))
const key = new Uint8Array(parseInt(byte, 10))
key.fill(5)
const iv = Buffer.alloc(16)
const iv = new Uint8Array(16)
iv.fill(1)
const cipher = await crypto.aes.create(key, iv)
for (let i = 0; i < fixtures[byte].inputs.length; i++) {
const rawIn = fixtures[byte].inputs[i]
const input = Buffer.from(rawIn)
const output = Buffer.from(fixtures[byte].outputs[i])
const input = Uint8Array.from(rawIn.data)
const output = Uint8Array.from(fixtures[byte].outputs[i].data)
const encrypted = await cipher.encrypt(input)
expect(encrypted).to.have.length(output.length)
expect(encrypted).to.eql(output)
@@ -65,18 +68,18 @@ describe('AES-CTR', () => {
}
it(`${bytes[byte]} - go interop - encrypt and decrypt`, async () => {
const key = Buffer.alloc(parseInt(byte, 10))
const key = new Uint8Array(parseInt(byte, 10))
key.fill(5)
const iv = Buffer.alloc(16)
const iv = new Uint8Array(16)
iv.fill(1)
const cipher = await crypto.aes.create(key, iv)
for (let i = 0; i < goFixtures[byte].inputs.length; i++) {
const rawIn = goFixtures[byte].inputs[i]
const input = Buffer.from(rawIn)
const output = Buffer.from(goFixtures[byte].outputs[i])
const input = Uint8Array.from(rawIn)
const output = Uint8Array.from(goFixtures[byte].outputs[i])
const encrypted = await cipher.encrypt(input)
expect(encrypted).to.have.length(output.length)
expect(encrypted).to.eql(output)
@@ -87,14 +90,18 @@ describe('AES-CTR', () => {
})
it('checks key length', () => {
const key = Buffer.alloc(5)
const iv = Buffer.alloc(16)
const key = new Uint8Array(5)
const iv = new Uint8Array(16)
return expectErrCode(crypto.aes.create(key, iv), 'ERR_INVALID_KEY_LENGTH')
})
})
// @ts-check
/**
* @type {function(Cipher): Promise<void>}
*/
async function encryptAndDecrypt (cipher) {
const data = Buffer.alloc(100)
const data = new Uint8Array(100)
data.fill(Math.ceil(Math.random() * 100))
const encrypted = await cipher.encrypt(data)

View File

@@ -2,9 +2,10 @@
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
chai.use(dirtyChai)
const uint8ArrayFromString = require('uint8arrays/from-string')
const crypto = require('../')
const webcrypto = require('../src/webcrypto')
@@ -36,7 +37,7 @@ describe('Missing web crypto', () => {
})
it('should error for hmac create when web crypto is missing', () => {
return expectMissingWebCrypto(() => crypto.hmac.create('SHA256', Buffer.from('secret')))
return expectMissingWebCrypto(() => crypto.hmac.create('SHA256', uint8ArrayFromString('secret')))
})
it('should error for generate ephemeral key pair when web crypto is missing', () => {
@@ -52,10 +53,10 @@ describe('Missing web crypto', () => {
})
it('should error for sign RSA private key when web crypto is missing', () => {
return expectMissingWebCrypto(() => rsaPrivateKey.sign(Buffer.from('test')))
return expectMissingWebCrypto(() => rsaPrivateKey.sign(uint8ArrayFromString('test')))
})
it('should error for verify RSA public key when web crypto is missing', () => {
return expectMissingWebCrypto(() => rsaPrivateKey.public.verify(Buffer.from('test'), Buffer.from('test')))
return expectMissingWebCrypto(() => rsaPrivateKey.public.verify(uint8ArrayFromString('test'), uint8ArrayFromString('test')))
})
})

View File

@@ -9,9 +9,16 @@ chai.use(dirtyChai)
const crypto = require('../src')
const fixtures = require('./fixtures/go-key-rsa')
const { expectErrCode } = require('./util')
const uint8ArrayEquals = require('uint8arrays/equals')
/** @typedef {import("libp2p-crypto").PrivateKey} PrivateKey */
describe('libp2p-crypto', function () {
this.timeout(20 * 1000)
// @ts-check
/**
* @type {PrivateKey}
*/
let key
before(async () => {
key = await crypto.keys.generateKeyPair('RSA', 512)
@@ -77,7 +84,7 @@ describe('libp2p-crypto', function () {
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)
expect(uint8ArrayEquals(fixtures.public.key, marshalled)).to.eql(true)
})
})
@@ -109,9 +116,9 @@ describe('libp2p-crypto', function () {
})
describe('randomBytes', () => {
it('throws with no number passed', () => {
it('throws with invalid number passed', () => {
expect(() => {
crypto.randomBytes()
crypto.randomBytes(-1)
}).to.throw()
})

View File

@@ -3,10 +3,10 @@
module.exports = {
curve: 'P-256',
bob: {
private: Buffer.from([
private: Uint8Array.from([
181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170
]),
public: Buffer.from([
public: Uint8Array.from([
4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90
])
}

View File

@@ -1,28 +1,42 @@
'use strict'
module.exports = {
// These were generated in a gore (https://github.com/motemen/gore) repl session:
// Generation code from https://github.com/libp2p/js-libp2p-crypto/issues/175#issuecomment-634467463
//
// :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)
// package main
//
// :import io/ioutil
// ioutil.WriteFile("/tmp/pubkey_go.bin", pubkeyBytes, 0644)
// // etc..
// import (
// "crypto/rand"
// "fmt"
// "strings"
// "github.com/libp2p/go-libp2p-core/crypto"
// )
// func main() {
// priv, pub, _ := crypto.GenerateEd25519Key(rand.Reader)
// pubkeyBytes, _ := pub.Bytes()
// privkeyBytes, _ := priv.Bytes()
// data := []byte("hello! and welcome to some awesome crypto primitives")
// sig, _ := priv.Sign(data)
// fmt.Println("{\n publicKey: Uint8Array.from(", strings.Replace(fmt.Sprint(pubkeyBytes), " ", ",", -1), "),")
// fmt.Println(" privateKey: Uint8Array.from(", strings.Replace(fmt.Sprint(privkeyBytes), " ", ",", -1), "),")
// fmt.Println(" data: Uint8Array.from(", strings.Replace(fmt.Sprint(data), " ", ",", -1), "),")
// fmt.Println(" signature: Uint8Array.from(", strings.Replace(fmt.Sprint(sig), " ", ",", -1), ")\n}")
// }
//
// 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))
// The legacy key unnecessarily appends the publickey. (It's already included) See https://github.com/libp2p/js-libp2p-crypto/issues/175
redundantPubKey: {
privateKey: Uint8Array.from([8, 1, 18, 96, 201, 208, 1, 110, 176, 16, 230, 37, 66, 184, 149, 252, 78, 56, 206, 136, 2, 38, 118, 152, 226, 197, 117, 200, 54, 189, 156, 218, 184, 7, 118, 57, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37]),
publicKey: Uint8Array.from([8, 1, 18, 32, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37]),
data: Uint8Array.from([104, 101, 108, 108, 111, 33, 32, 97, 110, 100, 32, 119, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 115, 111, 109, 101, 32, 97, 119, 101, 115, 111, 109, 101, 32, 99, 114, 121, 112, 116, 111, 32, 112, 114, 105, 109, 105, 116, 105, 118, 101, 115]),
signature: Uint8Array.from([7, 230, 175, 164, 228, 58, 78, 208, 62, 243, 73, 142, 83, 195, 176, 217, 166, 62, 41, 165, 168, 164, 75, 179, 163, 86, 102, 32, 18, 84, 150, 237, 39, 207, 213, 20, 134, 237, 50, 41, 176, 183, 229, 133, 38, 255, 42, 228, 68, 186, 100, 14, 175, 156, 243, 118, 125, 125, 120, 212, 124, 103, 252, 12])
},
verify: {
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])
publicKey: Uint8Array.from([8, 1, 18, 32, 163, 176, 195, 47, 254, 208, 49, 5, 192, 102, 32, 63, 58, 202, 171, 153, 146, 164, 25, 212, 25, 91, 146, 26, 117, 165, 148, 6, 207, 90, 217, 126]),
privateKey: Uint8Array.from([8, 1, 18, 64, 232, 56, 175, 20, 240, 160, 19, 47, 92, 88, 115, 221, 164, 13, 36, 162, 158, 136, 247, 31, 29, 231, 76, 143, 12, 91, 193, 4, 88, 33, 67, 23, 163, 176, 195, 47, 254, 208, 49, 5, 192, 102, 32, 63, 58, 202, 171, 153, 146, 164, 25, 212, 25, 91, 146, 26, 117, 165, 148, 6, 207, 90, 217, 126]),
data: Uint8Array.from([104, 101, 108, 108, 111, 33, 32, 97, 110, 100, 32, 119, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 115, 111, 109, 101, 32, 97, 119, 101, 115, 111, 109, 101, 32, 99, 114, 121, 112, 116, 111, 32, 112, 114, 105, 109, 105, 116, 105, 118, 101, 115]),
signature: Uint8Array.from([160, 125, 30, 62, 213, 189, 239, 92, 87, 76, 205, 169, 251, 149, 187, 57, 96, 85, 175, 213, 22, 132, 229, 60, 196, 18, 117, 194, 12, 174, 135, 31, 39, 168, 174, 103, 78, 55, 37, 222, 37, 172, 222, 239, 153, 63, 197, 152, 67, 167, 191, 215, 161, 212, 216, 163, 81, 77, 45, 228, 151, 79, 101, 1])
}
}

View File

@@ -2,29 +2,29 @@
module.exports = {
private: {
hash: Buffer.from([
hash: Uint8Array.from([
18, 32, 168, 125, 165, 65, 34, 157, 209, 4, 24, 158, 80, 196, 125, 86, 103, 0, 228, 145, 109, 252, 153, 7, 189, 9, 16, 37, 239, 36, 48, 78, 214, 212
]),
key: Buffer.from([
key: Uint8Array.from([
8, 0, 18, 192, 2, 48, 130, 1, 60, 2, 1, 0, 2, 65, 0, 230, 157, 160, 242, 74, 222, 87, 0, 77, 180, 91, 175, 217, 166, 2, 95, 193, 239, 195, 140, 224, 57, 84, 207, 46, 172, 113, 196, 20, 133, 117, 205, 45, 7, 224, 41, 40, 195, 254, 124, 14, 84, 223, 147, 67, 198, 48, 36, 53, 161, 112, 46, 153, 90, 19, 123, 94, 247, 5, 116, 1, 238, 32, 15, 2, 3, 1, 0, 1, 2, 65, 0, 191, 59, 140, 255, 254, 23, 123, 91, 148, 19, 240, 71, 213, 26, 181, 51, 68, 181, 150, 153, 214, 65, 148, 83, 45, 103, 239, 250, 225, 237, 125, 173, 111, 244, 37, 124, 87, 178, 86, 10, 14, 207, 63, 105, 213, 37, 81, 23, 230, 4, 222, 179, 144, 40, 252, 163, 190, 7, 241, 221, 28, 54, 225, 209, 2, 33, 0, 235, 132, 229, 150, 99, 182, 176, 194, 198, 65, 210, 160, 184, 70, 82, 49, 235, 199, 14, 11, 92, 66, 237, 45, 220, 72, 235, 1, 244, 145, 205, 57, 2, 33, 0, 250, 171, 146, 180, 188, 194, 14, 152, 52, 64, 38, 52, 158, 86, 46, 109, 66, 100, 122, 43, 88, 167, 143, 98, 104, 143, 160, 60, 171, 185, 31, 135, 2, 33, 0, 206, 47, 255, 203, 100, 170, 137, 31, 75, 240, 78, 84, 212, 95, 4, 16, 158, 73, 27, 27, 136, 255, 50, 163, 166, 169, 211, 204, 87, 111, 217, 201, 2, 33, 0, 177, 51, 194, 213, 3, 175, 7, 84, 47, 115, 189, 206, 106, 180, 47, 195, 203, 48, 110, 112, 224, 14, 43, 189, 124, 127, 51, 222, 79, 226, 225, 87, 2, 32, 67, 23, 190, 222, 106, 22, 115, 139, 217, 244, 178, 53, 153, 99, 5, 176, 72, 77, 193, 61, 67, 134, 37, 238, 69, 66, 159, 28, 39, 5, 238, 125
])
},
public: {
hash: Buffer.from([
hash: Uint8Array.from([
18, 32, 112, 151, 163, 167, 204, 243, 175, 123, 208, 162, 90, 84, 199, 174, 202, 110, 0, 119, 27, 202, 7, 149, 161, 251, 215, 168, 163, 54, 93, 54, 195, 20
]),
key: Buffer.from([
key: Uint8Array.from([
8, 0, 18, 94, 48, 92, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 75, 0, 48, 72, 2, 65, 0, 230, 157, 160, 242, 74, 222, 87, 0, 77, 180, 91, 175, 217, 166, 2, 95, 193, 239, 195, 140, 224, 57, 84, 207, 46, 172, 113, 196, 20, 133, 117, 205, 45, 7, 224, 41, 40, 195, 254, 124, 14, 84, 223, 147, 67, 198, 48, 36, 53, 161, 112, 46, 153, 90, 19, 123, 94, 247, 5, 116, 1, 238, 32, 15, 2, 3, 1, 0, 1
])
},
verify: {
signature: Buffer.from([
signature: Uint8Array.from([
3, 116, 81, 57, 91, 194, 7, 1, 230, 236, 229, 142, 36, 209, 208, 107, 47, 52, 164, 236, 139, 35, 155, 97, 43, 64, 145, 91, 19, 218, 149, 63, 99, 164, 191, 110, 145, 37, 18, 7, 98, 112, 144, 35, 29, 186, 169, 150, 165, 88, 145, 170, 197, 110, 42, 163, 188, 10, 42, 63, 34, 93, 91, 94, 199, 110, 10, 82, 238, 80, 93, 93, 77, 130, 22, 216, 229, 172, 36, 229, 82, 162, 20, 78, 19, 46, 82, 243, 43, 80, 115, 125, 145, 231, 194, 224, 30, 187, 55, 228, 74, 52, 203, 191, 254, 148, 136, 218, 62, 147, 171, 130, 251, 181, 105, 29, 238, 207, 197, 249, 61, 105, 202, 172, 160, 174, 43, 124, 115, 130, 169, 30, 76, 41, 52, 200, 2, 26, 53, 190, 43, 20, 203, 10, 217, 250, 47, 102, 92, 103, 197, 22, 108, 184, 74, 218, 82, 202, 180, 98, 13, 114, 12, 92, 1, 139, 150, 170, 8, 92, 32, 116, 168, 219, 157, 162, 28, 77, 29, 29, 74, 136, 144, 49, 173, 245, 253, 76, 167, 200, 169, 163, 7, 49, 133, 120, 99, 191, 53, 10, 66, 26, 234, 240, 139, 235, 134, 30, 55, 248, 150, 100, 242, 150, 159, 198, 44, 78, 150, 7, 133, 139, 59, 76, 3, 225, 94, 13, 89, 122, 34, 95, 95, 107, 74, 169, 171, 169, 222, 25, 191, 182, 148, 116, 66, 67, 102, 12, 193, 217, 247, 243, 148, 233, 161, 157
]),
data: Buffer.from([
data: Uint8Array.from([
10, 16, 27, 128, 228, 220, 147, 176, 53, 105, 175, 171, 32, 213, 35, 236, 203, 60, 18, 171, 2, 8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 181, 113, 138, 108, 208, 103, 166, 102, 37, 36, 204, 250, 228, 165, 44, 64, 176, 210, 205, 141, 241, 55, 200, 110, 98, 68, 85, 199, 254, 19, 86, 204, 63, 250, 167, 38, 59, 249, 146, 228, 73, 171, 63, 18, 96, 104, 191, 137, 186, 244, 255, 90, 16, 119, 195, 52, 177, 213, 254, 187, 174, 84, 174, 173, 12, 236, 53, 234, 3, 209, 82, 37, 78, 111, 214, 135, 76, 195, 9, 242, 134, 188, 153, 84, 139, 231, 51, 146, 177, 60, 12, 25, 158, 91, 215, 152, 7, 0, 84, 35, 36, 230, 227, 67, 198, 72, 50, 110, 37, 209, 98, 193, 65, 93, 173, 199, 4, 198, 102, 99, 148, 144, 224, 217, 114, 53, 144, 245, 251, 114, 211, 20, 82, 163, 123, 75, 16, 192, 106, 213, 128, 2, 11, 200, 203, 84, 41, 199, 224, 155, 171, 217, 64, 109, 116, 188, 151, 183, 173, 52, 205, 164, 93, 13, 251, 65, 182, 160, 154, 185, 239, 33, 184, 84, 159, 105, 101, 173, 194, 251, 123, 84, 92, 66, 61, 180, 45, 104, 162, 224, 214, 233, 64, 220, 165, 2, 104, 116, 150, 2, 234, 203, 112, 21, 124, 23, 48, 66, 30, 63, 30, 36, 246, 135, 203, 218, 115, 22, 189, 39, 39, 125, 205, 65, 222, 220, 77, 18, 84, 121, 161, 153, 125, 25, 139, 137, 170, 239, 150, 106, 119, 168, 216, 140, 113, 121, 26, 53, 118, 110, 53, 192, 244, 252, 145, 85, 2, 3, 1, 0, 1, 26, 17, 80, 45, 50, 53, 54, 44, 80, 45, 51, 56, 52, 44, 80, 45, 53, 50, 49, 34, 24, 65, 69, 83, 45, 50, 53, 54, 44, 65, 69, 83, 45, 49, 50, 56, 44, 66, 108, 111, 119, 102, 105, 115, 104, 42, 13, 83, 72, 65, 50, 53, 54, 44, 83, 72, 65, 53, 49, 50, 10, 16, 220, 83, 240, 105, 6, 203, 78, 83, 210, 115, 6, 106, 98, 82, 1, 161, 18, 171, 2, 8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 185, 234, 19, 191, 164, 33, 65, 94, 87, 42, 74, 83, 224, 25, 142, 44, 26, 7, 92, 242, 189, 42, 170, 197, 178, 92, 45, 240, 107, 141, 128, 59, 122, 252, 48, 140, 4, 85, 85, 203, 3, 197, 8, 127, 120, 98, 44, 169, 135, 196, 70, 137, 117, 180, 177, 134, 170, 35, 165, 88, 105, 30, 114, 138, 11, 96, 68, 99, 18, 149, 223, 166, 105, 12, 176, 77, 48, 214, 22, 236, 17, 154, 213, 209, 158, 169, 202, 5, 100, 210, 83, 90, 201, 38, 205, 246, 231, 106, 63, 86, 222, 143, 157, 173, 62, 4, 85, 232, 20, 188, 6, 209, 186, 132, 192, 117, 146, 181, 233, 26, 0, 240, 138, 206, 91, 170, 114, 137, 217, 132, 139, 242, 144, 213, 103, 101, 190, 146, 188, 250, 188, 134, 255, 70, 125, 78, 65, 136, 239, 190, 206, 139, 155, 140, 163, 233, 170, 247, 205, 87, 209, 19, 29, 173, 10, 147, 43, 28, 90, 46, 6, 197, 217, 186, 66, 68, 126, 76, 64, 184, 8, 170, 23, 79, 243, 223, 119, 133, 118, 50, 226, 44, 246, 176, 10, 161, 219, 83, 54, 68, 248, 5, 14, 177, 114, 54, 63, 11, 71, 136, 142, 56, 151, 123, 230, 61, 80, 15, 180, 42, 49, 220, 148, 99, 231, 20, 230, 220, 85, 207, 187, 37, 210, 137, 171, 125, 71, 14, 53, 100, 91, 83, 209, 50, 132, 165, 253, 25, 161, 5, 97, 164, 163, 83, 95, 53, 2, 3, 1, 0, 1, 26, 17, 80, 45, 50, 53, 54, 44, 80, 45, 51, 56, 52, 44, 80, 45, 53, 50, 49, 34, 15, 65, 69, 83, 45, 50, 53, 54, 44, 65, 69, 83, 45, 49, 50, 56, 42, 13, 83, 72, 65, 50, 53, 54, 44, 83, 72, 65, 53, 49, 50, 4, 97, 54, 203, 112, 136, 34, 231, 162, 19, 154, 131, 27, 105, 26, 121, 238, 120, 25, 203, 66, 232, 53, 198, 20, 19, 96, 119, 218, 90, 64, 170, 3, 132, 116, 1, 87, 116, 232, 165, 161, 198, 117, 167, 60, 145, 1, 253, 108, 50, 150, 117, 8, 140, 133, 48, 30, 236, 36, 84, 186, 22, 144, 87, 101
]),
publicKey: Buffer.from([
publicKey: Uint8Array.from([
8, 0, 18, 166, 2, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 181, 113, 138, 108, 208, 103, 166, 102, 37, 36, 204, 250, 228, 165, 44, 64, 176, 210, 205, 141, 241, 55, 200, 110, 98, 68, 85, 199, 254, 19, 86, 204, 63, 250, 167, 38, 59, 249, 146, 228, 73, 171, 63, 18, 96, 104, 191, 137, 186, 244, 255, 90, 16, 119, 195, 52, 177, 213, 254, 187, 174, 84, 174, 173, 12, 236, 53, 234, 3, 209, 82, 37, 78, 111, 214, 135, 76, 195, 9, 242, 134, 188, 153, 84, 139, 231, 51, 146, 177, 60, 12, 25, 158, 91, 215, 152, 7, 0, 84, 35, 36, 230, 227, 67, 198, 72, 50, 110, 37, 209, 98, 193, 65, 93, 173, 199, 4, 198, 102, 99, 148, 144, 224, 217, 114, 53, 144, 245, 251, 114, 211, 20, 82, 163, 123, 75, 16, 192, 106, 213, 128, 2, 11, 200, 203, 84, 41, 199, 224, 155, 171, 217, 64, 109, 116, 188, 151, 183, 173, 52, 205, 164, 93, 13, 251, 65, 182, 160, 154, 185, 239, 33, 184, 84, 159, 105, 101, 173, 194, 251, 123, 84, 92, 66, 61, 180, 45, 104, 162, 224, 214, 233, 64, 220, 165, 2, 104, 116, 150, 2, 234, 203, 112, 21, 124, 23, 48, 66, 30, 63, 30, 36, 246, 135, 203, 218, 115, 22, 189, 39, 39, 125, 205, 65, 222, 220, 77, 18, 84, 121, 161, 153, 125, 25, 139, 137, 170, 239, 150, 106, 119, 168, 216, 140, 113, 121, 26, 53, 118, 110, 53, 192, 244, 252, 145, 85, 2, 3, 1, 0, 1
])
}

31
test/fixtures/go-key-secp256k1.js vendored Normal file
View File

@@ -0,0 +1,31 @@
'use strict'
const uint8ArrayFromString = require('uint8arrays/from-string')
// The keypair and signature below were generated in a gore repl session (https://github.com/motemen/gore)
// using the secp256k1 fork of go-libp2p-crypto by github user @vyzo
//
// gore> :import github.com/vyzo/go-libp2p-crypto
// gore> :import crypto/rand
// gore> :import io/ioutil
// gore> priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Secp256k1, 256, rand.Reader)
// gore> privBytes, err := priv.Bytes()
// gore> pubBytes, err := pub.Bytes()
// gore> msg := []byte("hello! and welcome to some awesome crypto primitives")
// gore> sig, err := priv.Sign(msg)
// gore> ioutil.WriteFile("/tmp/secp-go-priv.bin", privBytes, 0644)
// gore> ioutil.WriteFile("/tmp/secp-go-pub.bin", pubBytes, 0644)
// gore> ioutil.WriteFile("/tmp/secp-go-sig.bin", sig, 0644)
//
// The generated files were then read in a node repl with e.g.:
// > fs.readFileSync('/tmp/secp-go-pub.bin').toString('hex')
// '08021221029c0ce5d53646ed47112560297a3e59b78b8cbd4bae37c7a0c236eeb91d0fbeaf'
//
// and the results copy/pasted in here
module.exports = {
privateKey: uint8ArrayFromString('08021220358f15db8c2014d570e8e3a622454e2273975a3cca443ec0c45375b13d381d18', 'base16'),
publicKey: uint8ArrayFromString('08021221029c0ce5d53646ed47112560297a3e59b78b8cbd4bae37c7a0c236eeb91d0fbeaf', 'base16'),
message: uint8ArrayFromString('hello! and welcome to some awesome crypto primitives'),
signature: uint8ArrayFromString('304402200e4c629e9f5d99439115e60989cd40087f6978c36078b0b50cf3d30af5c38d4102204110342c8e7f0809897c1c7a66e49e1c6b7cb0a6ed6993640ec2fe742c1899a9', 'base16')
}

View File

@@ -3,28 +3,28 @@
module.exports = [{
cipher: 'AES-256',
hash: 'SHA256',
secret: Buffer.from([
secret: Uint8Array.from([
195, 191, 209, 165, 209, 201, 127, 122, 136, 111, 31, 66, 111, 68, 38, 155, 216, 204, 46, 181, 200, 188, 170, 204, 104, 74, 239, 251, 173, 114, 222, 234
]),
k1: {
iv: Buffer.from([
iv: Uint8Array.from([
208, 132, 203, 169, 253, 52, 40, 83, 161, 91, 17, 71, 33, 136, 67, 96
]),
cipherKey: Buffer.from([
cipherKey: Uint8Array.from([
156, 48, 241, 157, 92, 248, 153, 186, 114, 127, 195, 114, 106, 104, 215, 133, 35, 11, 131, 137, 123, 70, 74, 26, 15, 60, 189, 32, 67, 221, 115, 137
]),
macKey: Buffer.from([
macKey: Uint8Array.from([
6, 179, 91, 245, 224, 56, 153, 120, 77, 140, 29, 5, 15, 213, 187, 65, 137, 230, 202, 120
])
},
k2: {
iv: Buffer.from([
iv: Uint8Array.from([
236, 17, 34, 141, 90, 106, 197, 56, 197, 184, 157, 135, 91, 88, 112, 19
]),
cipherKey: Buffer.from([
cipherKey: Uint8Array.from([
151, 145, 195, 219, 76, 195, 102, 109, 187, 231, 100, 150, 132, 245, 251, 130, 254, 37, 178, 55, 227, 34, 114, 39, 238, 34, 2, 193, 107, 130, 32, 87
]),
macKey: Buffer.from([
macKey: Uint8Array.from([
3, 229, 77, 212, 241, 217, 23, 113, 220, 126, 38, 255, 18, 117, 108, 205, 198, 89, 1, 236
])
}

View File

@@ -1,8 +1,10 @@
'use strict'
const uint8ArrayFromString = require('uint8arrays/from-string')
module.exports = {
// protobuf marshaled key pair generated with libp2p-crypto-secp256k1
// and marshaled with libp2p-crypto.marshalPublicKey / marshalPrivateKey
pbmPrivateKey: Buffer.from('08021220e0600103010000000100000000000000be1dc82c2e000000e8d6030301000000', 'hex'),
pbmPublicKey: Buffer.from('0802122103a9a7272a726fa083abf31ba44037f8347fbc5e5d3113d62a7c6bc26752fd8ee1', 'hex')
pbmPrivateKey: uint8ArrayFromString('08021220e0600103010000000100000000000000be1dc82c2e000000e8d6030301000000', 'base16'),
pbmPublicKey: uint8ArrayFromString('0802122103a9a7272a726fa083abf31ba44037f8347fbc5e5d3113d62a7c6bc26752fd8ee1', 'base16')
}

View File

@@ -1,8 +1,9 @@
/* eslint-env mocha */
'use strict'
const uint8ArrayFromString = require('uint8arrays/from-string')
const util = require('util')
const garbage = [Buffer.from('00010203040506070809', 'hex'), {}, null, false, undefined, true, 1, 0, Buffer.from(''), 'aGVsbG93b3JsZA==', 'helloworld', '']
const garbage = [uint8ArrayFromString('00010203040506070809', 'base16'), {}, null, false, undefined, true, 1, 0, uint8ArrayFromString(''), 'aGVsbG93b3JsZA==', 'helloworld', '']
function doTests (fncName, fnc, num, skipBuffersAndStrings) {
if (!num) {
@@ -10,8 +11,8 @@ function doTests (fncName, fnc, num, skipBuffersAndStrings) {
}
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
if (skipBuffersAndStrings && (garbage instanceof Uint8Array || (typeof garbage) === 'string')) {
// skip this garbage because it's a Uint8Array or a String and we were told do do that
return
}
const args = []

View File

@@ -6,6 +6,7 @@ const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const uint8ArrayFromString = require('uint8arrays/from-string')
const crypto = require('../../src')
@@ -14,8 +15,8 @@ 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'))
const hmac = await crypto.hmac.create(hash, uint8ArrayFromString('secret'))
const sig = await hmac.digest(uint8ArrayFromString('hello world'))
expect(sig).to.have.length(hmac.length)
})
})

View File

@@ -5,6 +5,7 @@ const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const uint8ArrayFromString = require('uint8arrays/from-string')
const crypto = require('../../src')
const ed25519 = crypto.keys.supportedKeys.ed25519
@@ -12,8 +13,14 @@ const fixtures = require('../fixtures/go-key-ed25519')
const testGarbage = require('../helpers/test-garbage-error-handling')
/** @typedef {import("libp2p-crypto").PrivateKey} PrivateKey */
describe('ed25519', function () {
this.timeout(20 * 1000)
// @ts-check
/**
* @type {PrivateKey}
*/
let key
before(async () => {
key = await crypto.keys.generateKeyPair('Ed25519', 512)
@@ -73,9 +80,29 @@ describe('ed25519', function () {
})
it('key id', async () => {
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
const id = await key.id()
expect(id).to.exist()
expect(id).to.be.a('string')
expect(id).to.eql('12D3KooWLqLxEfJ9nDdEe8Kh8PFvNPQRYDQBwyL7CMM7HhVd5LsX')
})
it('should export a password encrypted libp2p-key', async () => {
const key = await crypto.keys.generateKeyPair('Ed25519')
const encryptedKey = await key.export('my secret')
// Import the key
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
expect(key.equals(importedKey)).to.equal(true)
})
it('should fail to import libp2p-key with wrong password', async () => {
const key = await crypto.keys.generateKeyPair('Ed25519')
const encryptedKey = await key.export('my secret', 'libp2p-key')
try {
await crypto.keys.import(encryptedKey, 'not my secret')
} catch (err) {
expect(err).to.exist()
return
}
expect.fail('should have thrown')
})
describe('key equals', () => {
@@ -103,42 +130,56 @@ describe('ed25519', function () {
})
it('sign and verify', async () => {
const data = Buffer.from('hello world')
const data = uint8ArrayFromString('hello world')
const sig = await key.sign(data)
const valid = await key.public.verify(data, sig)
expect(valid).to.eql(true)
})
it('fails to verify for different data', async () => {
const data = Buffer.from('hello world')
const data = uint8ArrayFromString('hello world')
const sig = await key.sign(data)
const valid = await key.public.verify(Buffer.from('hello'), sig)
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
expect(valid).to.be.eql(false)
})
describe('throws error instead of crashing', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
testGarbage.doTests('key.verify', key.verify.bind(key), 2)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
testGarbage.doTests('key.verify', key.verify.bind(key), 2, null)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys), null, null)
})
describe('go interop', () => {
let privateKey
before(async () => {
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
privateKey = key
})
// @ts-check
it('verifies with data from go', async () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
const ok = await key.verify(fixtures.verify.data, fixtures.verify.signature)
expect(ok).to.eql(true)
})
it('does not include the redundant public key when marshalling privatekey', async () => {
const key = await crypto.keys.unmarshalPrivateKey(fixtures.redundantPubKey.privateKey)
const bytes = key.marshal()
expect(bytes.length).to.equal(64)
expect(bytes.slice(32)).to.eql(key.public.marshal())
})
it('verifies with data from go with redundant public key', async () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.redundantPubKey.publicKey)
const ok = await key.verify(fixtures.redundantPubKey.data, fixtures.redundantPubKey.signature)
expect(ok).to.eql(true)
})
it('generates the same signature as go', async () => {
const sig = await privateKey.sign(fixtures.verify.data)
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
const sig = await key.sign(fixtures.verify.data)
expect(sig).to.eql(fixtures.verify.signature)
})
it('generates the same signature as go with redundant public key', async () => {
const key = await crypto.keys.unmarshalPrivateKey(fixtures.redundantPubKey.privateKey)
const sig = await key.sign(fixtures.redundantPubKey.data)
expect(sig).to.eql(fixtures.redundantPubKey.signature)
})
})
})

View File

@@ -11,6 +11,10 @@ const fixtures = require('../fixtures/go-elliptic-key')
const crypto = require('../../src')
const curves = ['P-256', 'P-384'] // 'P-521' fails in tests :( no clue why
// @ts-check
/**
* @type {Record<string, number>}
*/
const lengths = {
'P-256': 65,
'P-384': 97,

View File

@@ -15,6 +15,10 @@ describe('keyStretcher', () => {
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
const hashes = ['SHA1', 'SHA256', 'SHA512']
let res
// @ts-check
/**
* @type {Uint8Array}
*/
let secret
before(async () => {

View File

@@ -8,6 +8,7 @@ const expect = chai.expect
chai.use(dirtyChai)
chai.use(require('chai-string'))
const { expectErrCode } = require('../util')
const uint8ArrayFromString = require('uint8arrays/from-string')
const crypto = require('../../src')
const rsa = crypto.keys.supportedKeys.rsa
@@ -15,12 +16,18 @@ const fixtures = require('../fixtures/go-key-rsa')
const testGarbage = require('../helpers/test-garbage-error-handling')
/** @typedef {import('libp2p-crypto').keys.supportedKeys.rsa.RsaPrivateKey} RsaPrivateKey */
describe('RSA', function () {
this.timeout(20 * 1000)
// @ts-check
/**
* @type {RsaPrivateKey}
*/
let key
before(async () => {
key = await crypto.keys.generateKeyPair('RSA', 512)
key = await rsa.generateKeyPair(512)
})
it('generates a valid key', async () => {
@@ -52,9 +59,9 @@ describe('RSA', function () {
})
it('key id', async () => {
const key = await crypto.keys.unmarshalPrivateKey(uint8ArrayFromString('CAASqAkwggSkAgEAAoIBAQCk0O+6oNRxhcdZe2GxEDrFBkDV4TZFZnp2ly/dL1cGMBql/8oXPZgei6h7+P5zzfDq2YCfwbjbf0IVY1AshRl6B5VGE1WS+9p1y1OZxJf5os6V1ENnTi6FTcyuBl4BN8dmIKOif0hqgqflaT5OhfYZDXfbJyVQj4vb2+Stu2Xpph3nwqAnTw/7GC/7jrt2Cq6Tu1PoZi36wSwEPYW3eQ1HAYxZjTYYDXl2iyHygnTcbkGRwAQ7vjk+mW7u60zyoolCm9f6Y7c/orJ33DDUocbaGJLlHcfd8bioBwaZy/2m7q43X8pQs0Q1/iwUt0HHZj1YARmHKbh0zR31ciFiV37dAgMBAAECggEADtJBNKnA4QKURj47r0YT2uLwkqtBi6UnDyISalQXAdXyl4n0nPlrhBewC5H9I+HZr+zmTbeIjaiYgz7el1pSy7AB4v7bG7AtWZlyx6mvtwHGjR+8/f3AXjl8Vgv5iSeAdXUq8fJ7SyS7v3wi38HZOzCEXj9bci6ud5ODMYJgLE4gZD0+i1+/V9cpuYfGpS/gLTLEMQLiw/9o8NSZ7sAnxg0UlYhotqaQY23hvXPBOe+0oa95zl2n6XTxCafa3dQl/B6CD1tUq9dhbQew4bxqMq/mhRO9pREEqZ083Uh+u4PTc1BeHgIQaS864pHPb+AY1F7KDvPtHhdojnghp8d70QKBgQDeRYFxo6sd04ohY86Z/i9icVYIyCvfXAKnaMKeGUjK7ou6sDJwFX8W97+CzXpZ/vffsk/l5GGhC50KqrITxHAy/h5IjyDODfps7NMIp0Dm9sO4PWibbw3OOVBRc8w3b3i7I8MrUUA1nLHE1T1HA1rKOTz5jYhE0fi9XKiT1ciKOQKBgQC903w+n9y7M7eaMW7Z5/13kZ7PS3HlM681eaPrk8J4J+c6miFF40/8HOsmarS38v0fgTeKkriPz5A7aLzRHhSiOnp350JNM6c3sLwPEs2qx/CRuWWx1rMERatfDdUH6mvlK6QHu0QgSfQR27EO6a6XvVSJXbvFmimjmtIaz/IpxQKBgQDWJ9HYVAGC81abZTaiWK3/A4QJYhQjWNuVwPICsgnYvI4Uib+PDqcs0ffLZ38DRw48kek5bxpBuJbOuDhro1EXUJCNCJpq7jzixituovd9kTRyR3iKii2bDM2+LPwOTXDdnk9lZRugjCEbrPkleq33Ob7uEtfAty4aBTTHe6uEwQKBgQCB+2q8RyMSXNuADhFlzOFXGrOwJm0bEUUMTPrduRQUyt4e1qOqA3klnXe3mqGcxBpnlEe/76/JacvNom6Ikxx16a0qpYRU8OWz0KU1fR6vrrEgV98241k5t6sdL4+MGA1Bo5xyXtzLb1hdUh3vpDwVU2OrnC+To3iXus/b5EBiMQKBgEI1OaBcFiyjgLGEyFKoZbtzH1mdatTExfrAQqCjOVjQByoMpGhHTXwEaosvyYu63Pa8AJPT7juSGaiKYEJFcXO9BiNyVfmQiqSHJcYeuh+fmO9IlHRHgy5xaIIC00AHS2vC/gXwmXAdPis6BZqDJeiCuOLWJ94QXn8JBT8IgGAI', 'base64pad'))
const id = await key.id()
expect(id).to.exist()
expect(id).to.be.a('string')
expect(id).to.eql('QmQgsppVMDUpe83wcAqaemKbYvHeF127gnSFQ1xFnBodVw')
})
describe('key equals', () => {
@@ -74,36 +81,40 @@ describe('RSA', function () {
})
it('sign and verify', async () => {
const data = Buffer.from('hello world')
const data = uint8ArrayFromString('hello world')
const sig = await key.sign(data)
const valid = await key.public.verify(data, sig)
expect(valid).to.be.eql(true)
})
it('encrypt and decrypt', async () => {
const data = Buffer.from('hello world')
const data = uint8ArrayFromString('hello world')
const enc = await key.public.encrypt(data)
const dec = await key.decrypt(enc)
expect(dec).to.be.eql(data)
})
it('encrypt decrypt browser/node interop', async () => {
const id = await crypto.keys.unmarshalPrivateKey(Buffer.from('CAASqAkwggSkAgEAAoIBAQCk0O+6oNRxhcdZe2GxEDrFBkDV4TZFZnp2ly/dL1cGMBql/8oXPZgei6h7+P5zzfDq2YCfwbjbf0IVY1AshRl6B5VGE1WS+9p1y1OZxJf5os6V1ENnTi6FTcyuBl4BN8dmIKOif0hqgqflaT5OhfYZDXfbJyVQj4vb2+Stu2Xpph3nwqAnTw/7GC/7jrt2Cq6Tu1PoZi36wSwEPYW3eQ1HAYxZjTYYDXl2iyHygnTcbkGRwAQ7vjk+mW7u60zyoolCm9f6Y7c/orJ33DDUocbaGJLlHcfd8bioBwaZy/2m7q43X8pQs0Q1/iwUt0HHZj1YARmHKbh0zR31ciFiV37dAgMBAAECggEADtJBNKnA4QKURj47r0YT2uLwkqtBi6UnDyISalQXAdXyl4n0nPlrhBewC5H9I+HZr+zmTbeIjaiYgz7el1pSy7AB4v7bG7AtWZlyx6mvtwHGjR+8/f3AXjl8Vgv5iSeAdXUq8fJ7SyS7v3wi38HZOzCEXj9bci6ud5ODMYJgLE4gZD0+i1+/V9cpuYfGpS/gLTLEMQLiw/9o8NSZ7sAnxg0UlYhotqaQY23hvXPBOe+0oa95zl2n6XTxCafa3dQl/B6CD1tUq9dhbQew4bxqMq/mhRO9pREEqZ083Uh+u4PTc1BeHgIQaS864pHPb+AY1F7KDvPtHhdojnghp8d70QKBgQDeRYFxo6sd04ohY86Z/i9icVYIyCvfXAKnaMKeGUjK7ou6sDJwFX8W97+CzXpZ/vffsk/l5GGhC50KqrITxHAy/h5IjyDODfps7NMIp0Dm9sO4PWibbw3OOVBRc8w3b3i7I8MrUUA1nLHE1T1HA1rKOTz5jYhE0fi9XKiT1ciKOQKBgQC903w+n9y7M7eaMW7Z5/13kZ7PS3HlM681eaPrk8J4J+c6miFF40/8HOsmarS38v0fgTeKkriPz5A7aLzRHhSiOnp350JNM6c3sLwPEs2qx/CRuWWx1rMERatfDdUH6mvlK6QHu0QgSfQR27EO6a6XvVSJXbvFmimjmtIaz/IpxQKBgQDWJ9HYVAGC81abZTaiWK3/A4QJYhQjWNuVwPICsgnYvI4Uib+PDqcs0ffLZ38DRw48kek5bxpBuJbOuDhro1EXUJCNCJpq7jzixituovd9kTRyR3iKii2bDM2+LPwOTXDdnk9lZRugjCEbrPkleq33Ob7uEtfAty4aBTTHe6uEwQKBgQCB+2q8RyMSXNuADhFlzOFXGrOwJm0bEUUMTPrduRQUyt4e1qOqA3klnXe3mqGcxBpnlEe/76/JacvNom6Ikxx16a0qpYRU8OWz0KU1fR6vrrEgV98241k5t6sdL4+MGA1Bo5xyXtzLb1hdUh3vpDwVU2OrnC+To3iXus/b5EBiMQKBgEI1OaBcFiyjgLGEyFKoZbtzH1mdatTExfrAQqCjOVjQByoMpGhHTXwEaosvyYu63Pa8AJPT7juSGaiKYEJFcXO9BiNyVfmQiqSHJcYeuh+fmO9IlHRHgy5xaIIC00AHS2vC/gXwmXAdPis6BZqDJeiCuOLWJ94QXn8JBT8IgGAI', 'base64'))
// @ts-check
/**
* @type {any}
*/
const id = await crypto.keys.unmarshalPrivateKey(uint8ArrayFromString('CAASqAkwggSkAgEAAoIBAQCk0O+6oNRxhcdZe2GxEDrFBkDV4TZFZnp2ly/dL1cGMBql/8oXPZgei6h7+P5zzfDq2YCfwbjbf0IVY1AshRl6B5VGE1WS+9p1y1OZxJf5os6V1ENnTi6FTcyuBl4BN8dmIKOif0hqgqflaT5OhfYZDXfbJyVQj4vb2+Stu2Xpph3nwqAnTw/7GC/7jrt2Cq6Tu1PoZi36wSwEPYW3eQ1HAYxZjTYYDXl2iyHygnTcbkGRwAQ7vjk+mW7u60zyoolCm9f6Y7c/orJ33DDUocbaGJLlHcfd8bioBwaZy/2m7q43X8pQs0Q1/iwUt0HHZj1YARmHKbh0zR31ciFiV37dAgMBAAECggEADtJBNKnA4QKURj47r0YT2uLwkqtBi6UnDyISalQXAdXyl4n0nPlrhBewC5H9I+HZr+zmTbeIjaiYgz7el1pSy7AB4v7bG7AtWZlyx6mvtwHGjR+8/f3AXjl8Vgv5iSeAdXUq8fJ7SyS7v3wi38HZOzCEXj9bci6ud5ODMYJgLE4gZD0+i1+/V9cpuYfGpS/gLTLEMQLiw/9o8NSZ7sAnxg0UlYhotqaQY23hvXPBOe+0oa95zl2n6XTxCafa3dQl/B6CD1tUq9dhbQew4bxqMq/mhRO9pREEqZ083Uh+u4PTc1BeHgIQaS864pHPb+AY1F7KDvPtHhdojnghp8d70QKBgQDeRYFxo6sd04ohY86Z/i9icVYIyCvfXAKnaMKeGUjK7ou6sDJwFX8W97+CzXpZ/vffsk/l5GGhC50KqrITxHAy/h5IjyDODfps7NMIp0Dm9sO4PWibbw3OOVBRc8w3b3i7I8MrUUA1nLHE1T1HA1rKOTz5jYhE0fi9XKiT1ciKOQKBgQC903w+n9y7M7eaMW7Z5/13kZ7PS3HlM681eaPrk8J4J+c6miFF40/8HOsmarS38v0fgTeKkriPz5A7aLzRHhSiOnp350JNM6c3sLwPEs2qx/CRuWWx1rMERatfDdUH6mvlK6QHu0QgSfQR27EO6a6XvVSJXbvFmimjmtIaz/IpxQKBgQDWJ9HYVAGC81abZTaiWK3/A4QJYhQjWNuVwPICsgnYvI4Uib+PDqcs0ffLZ38DRw48kek5bxpBuJbOuDhro1EXUJCNCJpq7jzixituovd9kTRyR3iKii2bDM2+LPwOTXDdnk9lZRugjCEbrPkleq33Ob7uEtfAty4aBTTHe6uEwQKBgQCB+2q8RyMSXNuADhFlzOFXGrOwJm0bEUUMTPrduRQUyt4e1qOqA3klnXe3mqGcxBpnlEe/76/JacvNom6Ikxx16a0qpYRU8OWz0KU1fR6vrrEgV98241k5t6sdL4+MGA1Bo5xyXtzLb1hdUh3vpDwVU2OrnC+To3iXus/b5EBiMQKBgEI1OaBcFiyjgLGEyFKoZbtzH1mdatTExfrAQqCjOVjQByoMpGhHTXwEaosvyYu63Pa8AJPT7juSGaiKYEJFcXO9BiNyVfmQiqSHJcYeuh+fmO9IlHRHgy5xaIIC00AHS2vC/gXwmXAdPis6BZqDJeiCuOLWJ94QXn8JBT8IgGAI', 'base64pad'))
const msg = Buffer.from('hello')
const msg = uint8ArrayFromString('hello')
// browser
const dec1 = await id.decrypt(Buffer.from('YRFUDx8UjbWSfDS84cDA4WowaaOmd1qFNAv5QutodCKYb9uPtU/tDiAvJzOGu5DCJRo2J0l/35P2weiB4/C2Cb1aZgXKMx/QQC+2jSJiymhqcZaYerjTvkCFwkjCaqthoVo/YXxsaFZ1q7bdTZUDH1TaJR7hWfSyzyPcA8c0w43MIsw16pY8ZaPSclvnCwhoTg1JGjMk6te3we7+wR8QU7VrPhs54mZWxrpu3NQ8xZ6xQqIedsEiNhBUccrCSzYghgsP0Ae/8iKyGyl3U6IegsJNn8jcocvzOJrmU03rgIFPjvuBdaqB38xDSTjbA123KadB28jNoSZh18q/yH3ZIg==', 'base64'))
const dec1 = id.decrypt(uint8ArrayFromString('YRFUDx8UjbWSfDS84cDA4WowaaOmd1qFNAv5QutodCKYb9uPtU/tDiAvJzOGu5DCJRo2J0l/35P2weiB4/C2Cb1aZgXKMx/QQC+2jSJiymhqcZaYerjTvkCFwkjCaqthoVo/YXxsaFZ1q7bdTZUDH1TaJR7hWfSyzyPcA8c0w43MIsw16pY8ZaPSclvnCwhoTg1JGjMk6te3we7+wR8QU7VrPhs54mZWxrpu3NQ8xZ6xQqIedsEiNhBUccrCSzYghgsP0Ae/8iKyGyl3U6IegsJNn8jcocvzOJrmU03rgIFPjvuBdaqB38xDSTjbA123KadB28jNoSZh18q/yH3ZIg==', 'base64pad'))
expect(dec1).to.be.eql(msg)
// node
const dec2 = await id.decrypt(Buffer.from('e6yxssqXsWc27ozDy0PGKtMkCS28KwFyES2Ijz89yiz+w6bSFkNOhHPKplpPzgQEuNoUGdbseKlJFyRYHjIT8FQFBHZM8UgSkgoimbY5on4xSxXs7E5/+twjqKdB7oNveTaTf7JCwaeUYnKSjbiYFEawtMiQE91F8sTT7TmSzOZ48tUhnddAAZ3Ac/O3Z9MSAKOCDipi+JdZtXRT8KimGt36/7hjjosYmPuHR1Xy/yMTL6SMbXtBM3yAuEgbQgP+q/7kHMHji3/JvTpYdIUU+LVtkMusXNasRA+UWG2zAht18vqjFMsm9JTiihZw9jRHD4vxAhf75M992tnC+0ZuQg==', 'base64'))
const dec2 = id.decrypt(uint8ArrayFromString('e6yxssqXsWc27ozDy0PGKtMkCS28KwFyES2Ijz89yiz+w6bSFkNOhHPKplpPzgQEuNoUGdbseKlJFyRYHjIT8FQFBHZM8UgSkgoimbY5on4xSxXs7E5/+twjqKdB7oNveTaTf7JCwaeUYnKSjbiYFEawtMiQE91F8sTT7TmSzOZ48tUhnddAAZ3Ac/O3Z9MSAKOCDipi+JdZtXRT8KimGt36/7hjjosYmPuHR1Xy/yMTL6SMbXtBM3yAuEgbQgP+q/7kHMHji3/JvTpYdIUU+LVtkMusXNasRA+UWG2zAht18vqjFMsm9JTiihZw9jRHD4vxAhf75M992tnC+0ZuQg==', 'base64pad'))
expect(dec2).to.be.eql(msg)
})
it('fails to verify for different data', async () => {
const data = Buffer.from('hello world')
const data = uint8ArrayFromString('hello world')
const sig = await key.sign(data)
const valid = await key.public.verify(Buffer.from('hello'), sig)
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
expect(valid).to.be.eql(false)
})
@@ -124,6 +135,24 @@ describe('RSA', function () {
expect(key.equals(clone)).to.eql(true)
})
it('should export a password encrypted libp2p-key', async () => {
const encryptedKey = await key.export('my secret', 'libp2p-key')
// Import the key
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
expect(key.equals(importedKey)).to.equal(true)
})
it('should fail to import libp2p-key with wrong password', async () => {
const encryptedKey = await key.export('my secret', 'libp2p-key')
try {
await crypto.keys.import(encryptedKey, 'not my secret')
} catch (err) {
expect(err).to.exist()
return
}
expect.fail('should have thrown')
})
it('needs correct password', async () => {
const pem = await key.export('another secret')
try {
@@ -142,7 +171,12 @@ describe('RSA', function () {
describe('throws error instead of crashing', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
testGarbage.doTests('key.verify', key.verify.bind(key), 2, true)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
testGarbage.doTests(
'crypto.keys.unmarshalPrivateKey',
crypto.keys.unmarshalPrivateKey.bind(crypto.keys),
null,
null
)
})
describe('go interop', () => {

View File

@@ -5,76 +5,283 @@ 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')
const secp256k1 = crypto.keys.supportedKeys.secp256k1
const keysPBM = crypto.keys.keysPBM
const randomBytes = crypto.randomBytes
const secp256k1Crypto = require('../../src/keys/secp256k1')(randomBytes)
const uint8ArrayFromString = require('uint8arrays/from-string')
const fixtures = require('../fixtures/go-key-secp256k1')
describe('without libp2p-crypto-secp256k1 module present', () => {
before(() => {
sinon.replace(crypto.keys.supportedKeys, 'secp256k1', null)
describe('secp256k1 keys', () => {
let key
before(async () => {
key = await secp256k1.generateKeyPair()
})
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()
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
expect(key.public).to.be.an.instanceof(secp256k1.Secp256k1PublicKey)
const digest = await key.hash()
expect(digest).to.have.length(34)
const publicDigest = await key.public.hash()
expect(publicDigest).to.have.length(34)
})
it('protobuf encoding', async () => {
const key = await crypto.keys.generateKeyPair('secp256k1', 256)
expect(key).to.exist()
it('optionally accepts a `bits` argument when generating a key', async () => {
const _key = await secp256k1.generateKeyPair()
expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
})
const keyMarshal = crypto.keys.marshalPrivateKey(key)
const key2 = await crypto.keys.unmarshalPrivateKey(keyMarshal)
const keyMarshal2 = crypto.keys.marshalPrivateKey(key2)
it('signs', async () => {
const text = randomBytes(512)
const sig = await key.sign(text)
const res = await key.public.verify(text, sig)
expect(res).to.equal(true)
})
it('encoding', async () => {
const keyMarshal = key.marshal()
const key2 = await secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal)
const keyMarshal2 = key2.marshal()
expect(keyMarshal).to.eql(keyMarshal2)
const pk = key.public
const pkMarshal = crypto.keys.marshalPublicKey(pk)
const pk2 = crypto.keys.unmarshalPublicKey(pkMarshal)
const pkMarshal2 = crypto.keys.marshalPublicKey(pk2)
const pkMarshal = pk.marshal()
const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal)
const pkMarshal2 = pk2.marshal()
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('key id', async () => {
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
const id = await key.id()
expect(id).to.eql('QmPCyMBGEyifPtx5aa6k6wkY9N1eBf9vHK1eKfNc35q9uq')
})
it('unmarshals a secp256k1 public key', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.pbmPublicKey)
expect(key).to.exist()
it('should export a password encrypted libp2p-key', async () => {
const key = await crypto.keys.generateKeyPair('secp256k1')
const encryptedKey = await key.export('my secret')
// Import the key
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
expect(key.equals(importedKey)).to.equal(true)
})
it('should fail to import libp2p-key with wrong password', async () => {
const key = await crypto.keys.generateKeyPair('secp256k1')
const encryptedKey = await key.export('my secret', 'libp2p-key')
try {
await crypto.keys.import(encryptedKey, 'not my secret')
} catch (err) {
expect(err).to.exist()
return
}
expect.fail('should have thrown')
})
describe('key equals', () => {
it('equals itself', () => {
expect(key.equals(key)).to.eql(true)
expect(key.public.equals(key.public)).to.eql(true)
})
it('not equals other key', async () => {
const key2 = await secp256k1.generateKeyPair()
expect(key.equals(key2)).to.eql(false)
expect(key2.equals(key)).to.eql(false)
expect(key.public.equals(key2.public)).to.eql(false)
expect(key2.public.equals(key.public)).to.eql(false)
})
})
it('sign and verify', async () => {
const data = uint8ArrayFromString('hello world')
const sig = await key.sign(data)
const valid = await key.public.verify(data, sig)
expect(valid).to.eql(true)
})
it('fails to verify for different data', async () => {
const data = uint8ArrayFromString('hello world')
const sig = await key.sign(data)
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
expect(valid).to.eql(false)
})
})
describe('key generation error', () => {
let generateKey
let secp256k1
before(() => {
generateKey = secp256k1Crypto.generateKey
secp256k1 = require('../../src/keys/secp256k1-class')(keysPBM, randomBytes, secp256k1Crypto)
secp256k1Crypto.generateKey = () => { throw new Error('Error generating key') }
})
after(() => {
secp256k1Crypto.generateKey = generateKey
})
it('returns an error if key generation fails', async () => {
try {
await secp256k1.generateKeyPair()
} catch (err) {
return expect(err.message).to.equal('Error generating key')
}
throw new Error('Expected error to be thrown')
})
})
describe('handles generation of invalid key', () => {
let generateKey
let secp256k1
before(() => {
generateKey = secp256k1Crypto.generateKey
secp256k1 = require('../../src/keys/secp256k1-class')(keysPBM, randomBytes, secp256k1Crypto)
secp256k1Crypto.generateKey = () => uint8ArrayFromString('not a real key')
})
after(() => {
secp256k1Crypto.generateKey = generateKey
})
it('returns an error if key generator returns an invalid key', async () => {
try {
await secp256k1.generateKeyPair()
} catch (err) {
return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32')
}
throw new Error('Expected error to be thrown')
})
})
describe('crypto functions', () => {
let privKey
let pubKey
before(async () => {
privKey = await secp256k1Crypto.generateKey()
pubKey = secp256k1Crypto.computePublicKey(privKey)
})
it('generates valid keys', () => {
expect(() => {
secp256k1Crypto.validatePrivateKey(privKey)
secp256k1Crypto.validatePublicKey(pubKey)
}).to.not.throw()
})
it('does not validate an invalid key', () => {
expect(() => secp256k1Crypto.validatePublicKey(uint8ArrayFromString('42'))).to.throw()
expect(() => secp256k1Crypto.validatePrivateKey(uint8ArrayFromString('42'))).to.throw()
})
it('validates a correct signature', async () => {
const sig = await secp256k1Crypto.hashAndSign(privKey, uint8ArrayFromString('hello'))
const valid = await secp256k1Crypto.hashAndVerify(pubKey, sig, uint8ArrayFromString('hello'))
expect(valid).to.equal(true)
})
it('errors if given a null Uint8Array to sign', async () => {
try {
await secp256k1Crypto.hashAndSign(privKey, null)
} catch (err) {
return // expected
}
throw new Error('Expected error to be thrown')
})
it('errors when signing with an invalid key', async () => {
try {
await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello'))
} catch (err) {
return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32')
}
throw new Error('Expected error to be thrown')
})
it('errors if given a null Uint8Array to validate', async () => {
const sig = await secp256k1Crypto.hashAndSign(privKey, uint8ArrayFromString('hello'))
try {
await secp256k1Crypto.hashAndVerify(privKey, sig, null)
} catch (err) {
return // expected
}
throw new Error('Expected error to be thrown')
})
it('errors when validating a message with an invalid signature', async () => {
try {
await secp256k1Crypto.hashAndVerify(pubKey, uint8ArrayFromString('invalid-sig'), uint8ArrayFromString('hello'))
} catch (err) {
return expect(err.message).to.equal('Signature could not be parsed')
}
throw new Error('Expected error to be thrown')
})
it('errors when signing with an invalid key', async () => {
try {
await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello'))
} catch (err) {
return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32')
}
throw new Error('Expected error to be thrown')
})
it('throws when compressing an invalid public key', () => {
expect(() => secp256k1Crypto.compressPublicKey(uint8ArrayFromString('42'))).to.throw()
})
it('throws when decompressing an invalid public key', () => {
expect(() => secp256k1Crypto.decompressPublicKey(uint8ArrayFromString('42'))).to.throw()
})
it('compresses/decompresses a valid public key', () => {
const decompressed = secp256k1Crypto.decompressPublicKey(pubKey)
expect(decompressed).to.exist()
expect(decompressed.length).to.be.eql(65)
const recompressed = secp256k1Crypto.compressPublicKey(decompressed)
expect(recompressed).to.eql(pubKey)
})
})
describe('go interop', () => {
it('loads a private key marshaled by go-libp2p-crypto', async () => {
// we need to first extract the key data from the protobuf, which is
// normally handled by js-libp2p-crypto
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
expect(key.bytes).to.eql(fixtures.privateKey)
})
it('loads a public key marshaled by go-libp2p-crypto', () => {
const decoded = keysPBM.PublicKey.decode(fixtures.publicKey)
expect(decoded.Type).to.be.eql(keysPBM.KeyType.Secp256k1)
const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data)
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey)
expect(key.bytes).to.eql(fixtures.publicKey)
})
it('generates the same signature as go-libp2p-crypto', async () => {
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
const sig = await key.sign(fixtures.message)
expect(sig).to.eql(fixtures.signature)
})
})

View File

@@ -6,26 +6,33 @@ const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
require('node-forge/lib/jsbn')
const forge = require('node-forge/lib/forge')
const util = require('../src/util')
const BN = require('bn.js')
describe('Util', () => {
let bn
before((done) => {
bn = new BN('dead', 16)
done()
before(() => {
bn = new forge.jsbn.BigInteger('dead', 16)
})
it('toBase64', (done) => {
expect(util.toBase64(bn)).to.eql('3q0')
done()
it('should convert BigInteger to a uint base64url encoded string', () => {
expect(util.bigIntegerToUintBase64url(bn)).to.eql('3q0')
})
it('toBase64 zero padding', (done) => {
const bnpad = new BN('ff', 16)
expect(util.toBase64(bnpad, 2)).to.eql('AP8')
done()
it('should convert BigInteger to a uint base64url encoded string with padding', () => {
const bnpad = new forge.jsbn.BigInteger('ff', 16)
expect(util.bigIntegerToUintBase64url(bnpad, 2)).to.eql('AP8')
})
it('should convert base64url encoded string to BigInteger', () => {
const num = util.base64urlToBigInteger('3q0')
expect(num.equals(bn)).to.be.true()
})
it('should convert base64url encoded string to Uint8Array with padding', () => {
const buf = util.base64urlToBuffer('AP8', 2)
expect(Uint8Array.from([0, 255])).to.eql(buf)
})
})

View File

@@ -1,8 +1,13 @@
/* eslint-disable valid-jsdoc */
'use strict'
const chai = require('chai')
const expect = chai.expect
// @ts-check
/**
* @type {function(any, string): Promise<void>}
*/
const expectErrCode = async (p, code) => {
try {
await p

30
tsconfig.json Normal file
View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"target": "ES5",
"noImplicitAny": false,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowJs": true,
"checkJs": true,
"baseUrl": ".",
"paths": {
"libp2p-crypto": [
"./src",
"../../src",
"../src"
]
},
"types": ["node", "mocha", "chai"],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": ["./src/index.d.ts",],
"include": ["./test/**/*.spec.js"]
}