Compare commits

..

103 Commits

Author SHA1 Message Date
David Dias
f3cb8ced36 chore: release version v0.10.4 2017-12-01 08:42:19 +00:00
David Dias
0a6f63dce5 chore: update contributors 2017-12-01 08:42:18 +00:00
David Dias
0ce5f34a08 chore: gitignore 2017-12-01 08:42:06 +00:00
David Dias
a826968e71 chore: update deps 2017-12-01 08:41:45 +00:00
Maciej Krüger
7608fdd858 fix: catch error when unmarshaling instead of crashing (#113)
* test: Add failing tests

* fix: Fix some failing tests

* fix: various fixes on garbage error handling and respective tests

* tests: increased timeout for test timing out in CI

* tests: increasing test timeout to please the CI gods

* tests: increasing test timeout to please the CI gods

* fix: for when unMarshallPrivateKey is called with null or undefined key
2017-12-01 08:36:29 +00:00
David Dias
bf9b532067 chore: release version v0.10.3 2017-09-07 10:38:29 +01:00
David Dias
5296f8a42f chore: update contributors 2017-09-07 10:38:29 +01:00
Friedel Ziegelmayer
3a91ae2ed8 feat: switch protocol-buffers to protons (#110)
Ref https://github.com/ipfs/js-ipfs/issues/991
2017-09-07 10:37:56 +01:00
David Dias
e7c11a8e01 chore: release version v0.10.2 2017-09-06 08:30:10 +01:00
David Dias
9bb96dc2bf chore: update contributors 2017-09-06 08:30:09 +01:00
David Dias
957fdd37e9 fix: use regular protocol-buffers until protobufjs is fixed (#109) 2017-09-06 08:29:45 +01:00
Friedel Ziegelmayer
83257bc4bd feat(deps): upgrade to aegir@12 and browserify-aes@1.0.8 2017-09-05 15:28:43 +02:00
David Dias
cb7fae7fcc chore: release version v0.10.1 2017-09-05 11:08:46 +01:00
David Dias
7669847c17 chore: update contributors 2017-09-05 11:08:46 +01:00
Friedel Ziegelmayer
dc2793f138 fix: switch to protobufjs (#107)
rm unsafe-eval
2017-09-05 11:05:47 +01:00
David Dias
e0b916ace9 chore: release version v0.10.0 2017-09-03 12:19:51 +01:00
David Dias
0a71af7b89 chore: update contributors 2017-09-03 12:19:51 +01:00
David Dias
46adafb207 chore: update deps 2017-09-03 12:19:03 +01:00
David Dias
9e977c7d44 feat: p2p addrs situation (#106)
* chore: update deps

* chore: update gitignore

* chore: update CI

* chore: update deps
2017-09-03 12:18:18 +01:00
Friedel Ziegelmayer
f20267b962 feat: skip nextTick in nodeify (#103) 2017-08-17 06:38:26 +02:00
David Dias
1b6a070fa8 chore: release version v0.9.4 2017-07-22 13:26:07 -07:00
David Dias
1471e07bf9 chore: update contributors 2017-07-22 13:26:06 -07:00
David Dias
bc554d1407 fix: circular circular dep -> DI 2017-07-22 13:25:15 -07:00
David Dias
83d2d52205 chore: release version v0.9.3 2017-07-22 12:36:06 -07:00
David Dias
301c779f49 chore: update contributors 2017-07-22 12:36:06 -07:00
David Dias
d552fd423a chore: use ~ instead of ^ 2017-07-22 12:33:24 -07:00
David Dias
306504c386 chore: release version v0.9.2 2017-07-22 12:23:30 -07:00
David Dias
bf80e8e511 chore: update contributors 2017-07-22 12:23:29 -07:00
David Dias
4e619e60f5 chore: update deps 2017-07-22 12:21:55 -07:00
David Dias
a958f52a5c chore: release version v0.9.1 2017-07-22 11:37:45 -07:00
David Dias
dfc476c4f6 chore: update contributors 2017-07-22 11:37:45 -07:00
David Dias
71eb33a44f chore: update deps 2017-07-22 11:34:27 -07:00
David Dias
310733726e chore: update deps 2017-07-22 11:31:04 -07:00
David Dias
0efc94bd20 chore: release version v0.9.0 2017-07-22 11:02:48 -07:00
David Dias
68f4b5f496 chore: update contributors 2017-07-22 11:02:47 -07:00
David Dias
2f8e234044 refactor: the whole thing (#102) 2017-07-22 10:57:27 -07:00
David Dias
c2c6fde394 chore: update deps 2017-07-20 20:13:52 -07:00
Greenkeeper
14dde32177 chore(package): update chai to version 4.0.1 (#100)
https://greenkeeper.io/
2017-06-01 10:24:43 +01:00
Friedel Ziegelmayer
5bc30297de chore: release version v0.8.8 2017-04-11 11:34:11 +02:00
Friedel Ziegelmayer
a5ad8cf444 chore: update contributors 2017-04-11 11:34:11 +02:00
Jack Kleeman
be64372a5e fix(ecdh): allow base64 to be left-0-padded, needed for JWK format
Fixes #97
2017-04-11 11:14:00 +02:00
David Dias
2b0b7abd78 chore: release version v0.8.7 2017-03-21 15:07:57 +00:00
David Dias
17f2065d21 chore: update contributors 2017-03-21 15:07:57 +00:00
David Dias
2f065167fa chore: update aegir 2017-03-21 15:05:22 +00:00
Friedel Ziegelmayer
e0ecce18ce chore: release version v0.8.6 2017-03-03 21:44:03 +01:00
Friedel Ziegelmayer
cea1140ec6 chore: update contributors 2017-03-03 21:44:03 +01:00
Jack Kleeman
e5b7c1f622 feat(keys): implement generateKeyPairFromSeed for ed25519
Implement generateKeyPairFromSeed for ed25519 - this will produce the same keypair for the same seed (or first 32 bytes of reader) as given to GenerateKeyPairWithReader in go-libp2p.
2017-03-03 21:38:51 +01:00
Friedel Ziegelmayer
20326199d9 Merge pull request #80 from libp2p/greenkeeper/tweetnacl-1.0.0-rc.1
Update tweetnacl to the latest version 🚀
2017-02-24 17:56:59 +01:00
greenkeeper[bot]
4e56e1724f fix(package): update tweetnacl to version 1.0.0-rc.1
https://greenkeeper.io/
2017-02-22 11:39:32 +00:00
David Dias
7d63f698c0 chore: release version v0.8.5 2017-02-10 18:54:16 -08:00
David Dias
a49df7786c chore: update contributors 2017-02-10 18:54:16 -08:00
David Dias
c73adb00cc fix: add libp2p-crypto-secp256k1 2017-02-10 18:53:36 -08:00
David Dias
8a95de4700 chore: release version v0.8.4 2017-02-10 17:54:47 -08:00
David Dias
c35a65133f chore: update contributors 2017-02-10 17:54:47 -08:00
David Dias
4eb4aa05de fix: rm browserify-optional and transforms 2017-02-10 17:54:11 -08:00
David Dias
21f96a4eb7 chore: release version v0.8.3 2017-02-10 16:16:49 -08:00
David Dias
39b5124526 chore: update contributors 2017-02-10 16:16:49 -08:00
David Dias
93e50dde10 fix: browserify-optional needs to be dep 2017-02-10 16:16:11 -08:00
David Dias
e383da5d44 chore: release version v0.8.2 2017-02-10 10:28:44 -08:00
David Dias
9b687f380c chore: update contributors 2017-02-10 10:28:44 -08:00
Friedel Ziegelmayer
82abede64a fix: use browserify-optional (#72)
This works around the issue that browserify throws on missing modules.
2017-02-10 10:21:56 -08:00
David Dias
a56ab406e4 chore: release version v0.8.1 2017-02-09 08:32:12 -08:00
David Dias
d753941c6e chore: update contributors 2017-02-09 08:32:12 -08:00
David Dias
6022eb0838 chore: ^ to ~ 2017-02-09 08:29:55 -08:00
Dmitriy Ryajov
1c6d0912cd chore: removing --webworker from build steps 2017-02-09 12:14:26 +01:00
Friedel Ziegelmayer
e18804c31e chore: release version v0.8.0 2017-02-07 21:03:56 +01:00
Friedel Ziegelmayer
133a2c8833 chore: update contributors 2017-02-07 21:03:55 +01:00
Friedel Ziegelmayer
fad0865b2b chore: drop webworker flag 2017-02-07 20:46:58 +01:00
Friedel Ziegelmayer
4edef07182 Merge pull request #67 from libp2p/greenkeeper-aegir-10.0.0
Update aegir to version 10.0.0 🚀
2017-02-07 20:45:13 +01:00
Friedel Ziegelmayer
19c6ce7c06 Merge pull request #65 from dryajov/master
feat: change window to self for webworker support
2017-02-07 20:45:01 +01:00
Friedel Ziegelmayer
3fa76a874f Merge pull request #66 from libp2p/expose-proto
feat: expose protobuf
2017-02-07 20:44:36 +01:00
greenkeeperio-bot
6e0fd6f257 chore(package): update aegir to version 10.0.0
https://greenkeeper.io/
2017-02-07 18:45:52 +01:00
Friedel Ziegelmayer
c91d9b61c8 feat: expose protobuf
this allows other modules to reuse the protobuf definition
2017-02-07 17:51:43 +01:00
Yusef Napora
76eeb5aa18 feat: add support for secp256k1 keys through the libp2p-crypto-secp256k1 module 2017-02-04 10:23:38 +01:00
dryajov
843b5e33d6 WIP: use self instead of window for WebWorker compatibility 2017-01-31 02:09:46 -08:00
Friedel Ziegelmayer
308ac7cd1a chore: release version v0.7.7 2017-01-27 14:07:42 +01:00
Friedel Ziegelmayer
6c8f978ea4 chore: update contributors 2017-01-27 14:07:42 +01:00
Friedel Ziegelmayer
b93b410357 Merge pull request #63 from libp2p/dryajov-master
Dryajov master
2017-01-27 13:53:26 +01:00
Friedel Ziegelmayer
99a5245fa3 update deps 2017-01-27 12:15:19 +01:00
dryajov
34856d58ab removing contributors 2017-01-26 17:20:51 -08:00
dryajov
d59c6af7c0 Merge branch 'master' of https://github.com/libp2p/js-libp2p-crypto 2017-01-23 18:39:51 -08:00
dryajov
1683bf1dc8 reverting version 2017-01-23 18:32:52 -08:00
dryajov
a4edf8b99b chore: release version v0.7.6 2017-01-23 18:30:30 -08:00
dryajov
27524354af chore: update contributors 2017-01-23 18:30:30 -08:00
dryajov
a1f054ca8e adding webworker test task 2017-01-22 19:39:58 -08:00
dryajov
5c61c89391 fixing lint issues with self 2017-01-20 16:20:23 -08:00
David Dias
c138a04d2d chore: release version v0.7.6 2017-01-16 04:21:42 +00:00
David Dias
7c913c0769 chore: update contributors 2017-01-16 04:21:42 +00:00
Friedel Ziegelmayer
1a2d468369 fix: consistent buffer usage (#56)
* fix: consistent buffer usage

Closes #49

* more fixes for node 4
2017-01-16 05:17:50 +01:00
Tom Swindell
98bc0bbc5f Support for WebWorker.
Signed-off-by: Tom Swindell <t.swindell@rubyx.co.uk>
2017-01-14 12:45:52 +00:00
Yusef Napora
c45bdf602e feat(keys): add Ed25519 support for signing & verification
Closes #43
2016-12-23 14:52:40 +01:00
Greenkeeper
e92bab1736 chore(package): update node-webcrypto-ossl to version 1.0.15 (#54)
https://greenkeeper.io/
2016-12-18 11:37:21 +00:00
Friedel Ziegelmayer
c57d1e4d4f chore: release version v0.7.5 2016-12-13 12:56:43 +01:00
Friedel Ziegelmayer
04682acd86 chore: update contributors 2016-12-13 12:56:42 +01:00
Friedel Ziegelmayer
fba4833aef Merge pull request #53 from libp2p/fix/another-buffer-bites-the-dust
fix: use toArrayLike instead of toBuffer for browserify
2016-12-13 12:55:58 +01:00
Friedel Ziegelmayer
2842df7944 fix: use toArrayLike instead of toBuffer for browserify 2016-12-13 12:52:43 +01:00
Greenkeeper
74c0d28f86 chore(package): update aegir to version 9.2.1 (#50)
https://greenkeeper.io/
2016-12-10 11:59:47 -08:00
David Dias
cf7ed6fa49 chore: release version v0.7.4 2016-12-06 00:07:11 +00:00
David Dias
c1ffa41697 chore: update contributors 2016-12-06 00:07:11 +00:00
nikuda
933119445f fix(utils): make util.toBase64 browserify compatible
`bn.toArrayLike` is used instead of `bn.toBuffer`, to ensure compatibility with browserify.
2016-12-03 09:32:07 +01:00
David Dias
a4e6f9dd83 chore: release version v0.7.3 2016-12-01 11:43:46 +00:00
David Dias
e252db300c chore: update contributors 2016-12-01 11:43:46 +00:00
David Dias
98b37d49c4 feat: add randomBytes function (#45)
* feat: add randomBytes function

* fix: apply CR
2016-12-01 11:42:19 +00:00
55 changed files with 1655 additions and 792 deletions

1
.eslintignore Normal file
View File

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

13
.gitignore vendored
View File

@@ -1,6 +1,11 @@
docs
package-lock.json
yarn.lock
**/node_modules/ **/node_modules/
**/*.log **/*.log
test/repo-tests* test/repo-tests*
**/bundle.js
# Logs # Logs
logs logs
@@ -31,4 +36,12 @@ build
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules node_modules
lib
dist dist
test/test-data/go-ipfs-repo/LOCK
test/test-data/go-ipfs-repo/LOG
test/test-data/go-ipfs-repo/LOG.old
# while testing npm5
package-lock.json
yarn.lock

View File

@@ -3,32 +3,21 @@ language: node_js
matrix: matrix:
include: include:
- node_js: 4
env: CXX=g++-4.8
- node_js: 6 - node_js: 6
env:
- SAUCE=true
- CXX=g++-4.8
- node_js: stable
env: CXX=g++-4.8 env: CXX=g++-4.8
- node_js: 8
# Make sure we have new NPM. env: CXX=g++-4.8
before_install: # - node_js: stable
- npm install -g npm # env: CXX=g++-4.8
script: script:
- npm run lint - npm run lint
- npm test - npm run test
- npm run coverage
before_script: before_script:
- export DISPLAY=:99.0 - export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start - sh -e /etc/init.d/xvfb start
after_success:
- npm run coverage-publish
addons: addons:
firefox: 'latest' firefox: 'latest'
apt: apt:

116
CHANGELOG.md Normal file
View File

@@ -0,0 +1,116 @@
<a name="0.10.4"></a>
## [0.10.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.3...v0.10.4) (2017-12-01)
### Bug Fixes
* catch error when unmarshaling instead of crashing ([#113](https://github.com/libp2p/js-libp2p-crypto/issues/113)) ([7608fdd](https://github.com/libp2p/js-libp2p-crypto/commit/7608fdd))
<a name="0.10.3"></a>
## [0.10.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.2...v0.10.3) (2017-09-07)
### Features
* switch protocol-buffers to protons ([#110](https://github.com/libp2p/js-libp2p-crypto/issues/110)) ([3a91ae2](https://github.com/libp2p/js-libp2p-crypto/commit/3a91ae2))
<a name="0.10.2"></a>
## [0.10.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.1...v0.10.2) (2017-09-06)
### Bug Fixes
* use regular protocol-buffers until protobufjs is fixed ([#109](https://github.com/libp2p/js-libp2p-crypto/issues/109)) ([957fdd3](https://github.com/libp2p/js-libp2p-crypto/commit/957fdd3))
### Features
* **deps:** upgrade to aegir@12 and browserify-aes@1.0.8 ([83257bc](https://github.com/libp2p/js-libp2p-crypto/commit/83257bc))
<a name="0.10.1"></a>
## [0.10.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.0...v0.10.1) (2017-09-05)
### Bug Fixes
* switch to protobufjs ([#107](https://github.com/libp2p/js-libp2p-crypto/issues/107)) ([dc2793f](https://github.com/libp2p/js-libp2p-crypto/commit/dc2793f))
<a name="0.10.0"></a>
# [0.10.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.4...v0.10.0) (2017-09-03)
### Features
* p2p addrs situation ([#106](https://github.com/libp2p/js-libp2p-crypto/issues/106)) ([9e977c7](https://github.com/libp2p/js-libp2p-crypto/commit/9e977c7))
* skip nextTick in nodeify ([#103](https://github.com/libp2p/js-libp2p-crypto/issues/103)) ([f20267b](https://github.com/libp2p/js-libp2p-crypto/commit/f20267b))
<a name="0.9.4"></a>
## [0.9.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.3...v0.9.4) (2017-07-22)
### Bug Fixes
* circular circular dep -> DI ([bc554d1](https://github.com/libp2p/js-libp2p-crypto/commit/bc554d1))
<a name="0.9.3"></a>
## [0.9.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.2...v0.9.3) (2017-07-22)
<a name="0.9.2"></a>
## [0.9.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.1...v0.9.2) (2017-07-22)
<a name="0.9.1"></a>
## [0.9.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.0...v0.9.1) (2017-07-22)
<a name="0.9.0"></a>
# [0.9.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.8...v0.9.0) (2017-07-22)
<a name="0.8.8"></a>
## [0.8.8](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.7...v0.8.8) (2017-04-11)
### Bug Fixes
* **ecdh:** allow base64 to be left-0-padded, needed for JWK format ([be64372](https://github.com/libp2p/js-libp2p-crypto/commit/be64372)), closes [#97](https://github.com/libp2p/js-libp2p-crypto/issues/97)
<a name="0.8.7"></a>
## [0.8.7](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.6...v0.8.7) (2017-03-21)
<a name="0.8.6"></a>
## [0.8.6](https://github.com/libp2p/js-libp2p-crypto/compare/v0.8.5...v0.8.6) (2017-03-03)
### Bug Fixes
* **package:** update tweetnacl to version 1.0.0-rc.1 ([4e56e17](https://github.com/libp2p/js-libp2p-crypto/commit/4e56e17))
### Features
* **keys:** implement generateKeyPairFromSeed for ed25519 ([e5b7c1f](https://github.com/libp2p/js-libp2p-crypto/commit/e5b7c1f))

135
README.md
View File

@@ -10,38 +10,32 @@
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square) ![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square)
![](https://img.shields.io/badge/Node.js-%3E%3D4.0.0-orange.svg?style=flat-square) ![](https://img.shields.io/badge/Node.js-%3E%3D6.0.0-orange.svg?style=flat-square)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/ipfs-js-libp2p-crypto.svg)](https://saucelabs.com/u/ipfs-js-
libp2p-crypto)
> Crypto primitives for libp2p in JavaScript > Crypto primitives for libp2p in JavaScript
This repo contains the JavaScript implementation of the crypto primitives This repo contains the JavaScript implementation of the crypto primitives needed for libp2p. This is based on this [go implementation](https://github.com/libp2p/go-libp2p-crypto).
needed for libp2p. This is based on this [go implementation](https://github.com/libp2p/go-libp2p-crypto).
## Table of Contents ## Table of Contents
- [Install](#install) - [Install](#install)
- [Usage](#usage)
- [Example](#example)
- [API](#api) - [API](#api)
- [`hmac`](#hmac) - [`crypto.hmac`](#hmac)
- [`create(hash, secret, callback)`](#createhash-secret-callback) - [`create(hash, secret, callback)`](#createhash-secret-callback)
- [`digest(data, callback)`](#digestdata-callback) - [`digest(data, callback)`](#digestdata-callback)
- [`aes`](#aes) - [`crypto.aes`](#aes)
- [`create(key, iv, callback)`](#createkey-iv-callback) - [`create(key, iv, callback)`](#createkey-iv-callback)
- [`encrypt(data, callback)`](#encryptdata-callback) - [`encrypt(data, callback)`](#encryptdata-callback)
- [`encrypt(data, callback)`](#encryptdata-callback) - [`decrypt(data, callback)`](#decryptdata-callback)
- [`webcrypto`](#webcrypto)
- [`keys`](#keys) - [`keys`](#keys)
- [`generateKeyPair(type, bits, callback)`](#generatekeypairtype-bits-callback) - [`generateKeyPair(type, bits, callback)`](#generatekeypairtype-bits-callback)
- [`generateEphemeralKeyPair(curve, callback)`](#generateephemeralkeypaircurve-callback) - [`generateEphemeralKeyPair(curve, callback)`](#generateephemeralkeypaircurve-callback)
- [`keyStretcher(cipherType, hashType, secret, callback)`](#keystretcherciphertype-hashtype-secret-callback) - [`keyStretcher(cipherType, hashType, secret, callback)`](#keystretcherciphertype-hashtype-secret-callback)
- [`marshalPublicKey(key[, type], callback)`](#marshalpublickeykey-type-callback) - [`marshalPublicKey(key[, type], callback)`](#marshalpublickeykey-type-callback)
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf) - [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type) - [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
- [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback) - [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback)
- [`webcrypto`](#webcrypto)
- [Contribute](#contribute) - [Contribute](#contribute)
- [License](#license) - [License](#license)
@@ -51,24 +45,39 @@ needed for libp2p. This is based on this [go implementation](https://github.com/
npm install --save libp2p-crypto npm install --save libp2p-crypto
``` ```
## Usage
### Example
```js
const crypto = require('libp2p-crypto')
crypto.generateKeyPair('RSA', 2048, (err, key) => {
})
```
## API ## API
### `hmac` ### `crypto.aes`
Expoes an interface to AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.
This uses `CTR` mode.
#### `crypto.aes.create(key, iv, callback)`
- `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`.
- `callback: Function`
##### `decrypt(data, callback)`
- `data: Buffer`
- `callback: Function`
##### `encrypt(data, callback)`
- `data: Buffer`
- `callback: Function`
```
TODO: Example of using aes
```
### `crypto.hmac`
Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198. An HMAC is a cryptographic hash that uses a key to sign a message. The receiver verifies the hash by recomputing it using the same key. Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198. An HMAC is a cryptographic hash that uses a key to sign a message. The receiver verifies the hash by recomputing it using the same key.
#### `create(hash, secret, callback)` #### `crypto.hmac.create(hash, secret, callback)`
- `hash: String` - `hash: String`
- `secret: Buffer` - `secret: Buffer`
@@ -79,43 +88,31 @@ Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as def
- `data: Buffer` - `data: Buffer`
- `callback: Function` - `callback: Function`
### `aes` Example:
Expoes an interface to AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.
This uses `CTR` mode. ```
TODO: Example of using hmac
```
#### `create(key, iv, callback)` ### `crypto.keys`
- `key: Buffer` The key, if length `16` then `AES 128` is used. For length `32`, `AES 256` is used. **Supported Key Types**
- `iv: Buffer` Must have length `16`.
- `callback: Function`
##### `encrypt(data, callback)` The [`generateKeyPair`](#generatekeypairtype-bits-callback), [`marshalPublicKey`](#marshalpublickeykey-type-callback), and [`marshalPrivateKey`](#marshalprivatekeykey-type) functions accept a string `type` argument.
- `data: Buffer` 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.
- `callback: Function`
##### `encrypt(data, callback)` 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.
- `data: Buffer` ### `crypto.keys.generateKeyPair(type, bits, callback)`
- `callback: Function`
- `type: String`, see [Supported Key Types](#supported-key-types) above.
### `webcrypto`
Depending on the environment this is either an instance of [node-webcrypto-ossl](https://github.com/PeculiarVentures/node-webcrypto-ossl) or the result of `window.crypto`.
### `keys`
### `generateKeyPair(type, bits, callback)`
- `type: String`, only `'RSA'` is currently supported
- `bits: Number` Minimum of 1024 - `bits: Number` Minimum of 1024
- `callback: Function` - `callback: Function`
Generates a keypair of the given type and bitsize. Generates a keypair of the given type and bitsize.
### `generateEphemeralKeyPair(curve, callback)` ### `crypto.keys.generateEphemeralKeyPair(curve, callback)`
- `curve: String`, one of `'P-256'`, `'P-384'`, `'P-521'` is currently supported - `curve: String`, one of `'P-256'`, `'P-384'`, `'P-521'` is currently supported
- `callback: Function` - `callback: Function`
@@ -133,7 +130,7 @@ Calls back with an object of the form
} }
``` ```
### `keyStretcher(cipherType, hashType, secret, callback)` ### `crypto.keys.keyStretcher(cipherType, hashType, secret, callback)`
- `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'` - `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'`
- `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512` - `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512`
@@ -142,7 +139,8 @@ Calls back with an object of the form
Generates a set of keys for each party by stretching the shared key. Generates a set of keys for each party by stretching the shared key.
Calls back with an object of the form Calls back with an object of the form:
```js ```js
{ {
k1: { k1: {
@@ -158,33 +156,38 @@ Calls back with an object of the form
} }
``` ```
### `marshalPublicKey(key[, type], callback)` ### `crypto.keys.marshalPublicKey(key[, type], callback)`
- `key: crypto.rsa.RsaPublicKey` - `key: keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | require('libp2p-crypto-secp256k1').Secp256k1PublicKey`
- `type: String`, only `'RSA'` is currently supported - `type: String`, see [Supported Key Types](#supported-key-types) above.
Converts a public key object into a protobuf serialized public key. Converts a public key object into a protobuf serialized public key.
### `unmarshalPublicKey(buf)` ### `crypto.keys.unmarshalPublicKey(buf)`
- `buf: Buffer` - `buf: Buffer`
Converts a protobuf serialized public key into its representative object. Converts a protobuf serialized public key into its representative object.
### `marshalPrivateKey(key[, type])` ### `crypto.keys.marshalPrivateKey(key[, type])`
- `key: crypto.rsa.RsaPrivateKey` - `key: keys.rsa.RsaPrivateKey | keys.ed25519.Ed25519PrivateKey | require('libp2p-crypto-secp256k1').Secp256k1PrivateKey`
- `type: String`, only `'RSA'` is currently supported - `type: String`, see [Supported Key Types](#supported-key-types) above.
Converts a private key object into a protobuf serialized private key. Converts a private key object into a protobuf serialized private key.
### `unmarshalPrivateKey(buf, callback)` ### `crypto.keys.unmarshalPrivateKey(buf, callback)`
- `buf: Buffer` - `buf: Buffer`
- `callback: Function` - `callback: Function`
Converts a protobuf serialized private key into its representative object. Converts a protobuf serialized private key into its representative object.
### `crypto.randomBytes(number)`
- `number: Number`
Generates a Buffer with length `number` populated by random bytes.
## Contribute ## Contribute

View File

@@ -10,28 +10,18 @@ const curves = ['P-256', 'P-384', 'P-521']
curves.forEach((curve) => { curves.forEach((curve) => {
suite.add(`ephemeral key with secrect ${curve}`, (d) => { suite.add(`ephemeral key with secrect ${curve}`, (d) => {
crypto.generateEphemeralKeyPair('P-256', (err, res) => { crypto.keys.generateEphemeralKeyPair('P-256', (err, res) => {
if (err) { if (err) { throw err }
throw err
}
res.genSharedKey(res.key, (err, secret) => { res.genSharedKey(res.key, (err, secret) => {
if (err) { if (err) { throw err }
throw err
}
secrets.push(secret) secrets.push(secret)
d.resolve() d.resolve()
}) })
}) })
}, { }, { defer: true })
defer: true
})
}) })
suite suite
.on('cycle', (event) => { .on('cycle', (event) => console.log(String(event.target)))
console.log(String(event.target)) .run({async: true})
})
.run({
async: true
})

View File

@@ -13,37 +13,27 @@ const ciphers = ['AES-128', 'AES-256', 'Blowfish']
const hashes = ['SHA1', 'SHA256', 'SHA512'] const hashes = ['SHA1', 'SHA256', 'SHA512']
async.waterfall([ async.waterfall([
(cb) => crypto.generateEphemeralKeyPair('P-256', cb), (cb) => crypto.keys.generateEphemeralKeyPair('P-256', cb),
(res, cb) => res.genSharedKey(res.key, cb) (res, cb) => res.genSharedKey(res.key, cb)
], (err, secret) => { ], (err, secret) => {
if (err) { if (err) { throw err }
throw err
}
ciphers.forEach((cipher) => hashes.forEach((hash) => { ciphers.forEach((cipher) => hashes.forEach((hash) => {
setup(cipher, hash, secret) setup(cipher, hash, secret)
})) }))
suite suite
.on('cycle', (event) => { .on('cycle', (event) => console.log(String(event.target)))
console.log(String(event.target)) .run({async: true})
})
.run({
async: true
})
}) })
function setup (cipher, hash, secret) { function setup (cipher, hash, secret) {
suite.add(`keyStretcher ${cipher} ${hash}`, (d) => { suite.add(`keyStretcher ${cipher} ${hash}`, (d) => {
crypto.keyStretcher(cipher, hash, secret, (err, k) => { crypto.keys.keyStretcher(cipher, hash, secret, (err, k) => {
if (err) { if (err) { throw err }
throw err
}
keys.push(k) keys.push(k)
d.resolve() d.resolve()
}) })
}, { }, { defer: true })
defer: true
})
} }

View File

@@ -10,8 +10,8 @@ const bits = [1024, 2048, 4096]
bits.forEach((bit) => { bits.forEach((bit) => {
suite.add(`generateKeyPair ${bit}bits`, (d) => { suite.add(`generateKeyPair ${bit}bits`, (d) => {
crypto.generateKeyPair('RSA', bit, (err, key) => { crypto.keys.generateKeyPair('RSA', bit, (err, key) => {
if (err) throw err if (err) { throw err }
keys.push(key) keys.push(key)
d.resolve() d.resolve()
}) })
@@ -25,17 +25,11 @@ suite.add('sign and verify', (d) => {
const text = key.genSecret() const text = key.genSecret()
key.sign(text, (err, sig) => { key.sign(text, (err, sig) => {
if (err) { if (err) { throw err }
throw err
}
key.public.verify(text, sig, (err, res) => { key.public.verify(text, sig, (err, res) => {
if (err) { if (err) { throw err }
throw err if (res !== true) { throw new Error('failed to verify') }
}
if (res !== true) {
throw new Error('failed to verify')
}
d.resolve() d.resolve()
}) })
}) })
@@ -44,9 +38,5 @@ suite.add('sign and verify', (d) => {
}) })
suite suite
.on('cycle', (event) => { .on('cycle', (event) => console.log(String(event.target)))
console.log(String(event.target)) .run({async: true})
})
.run({
async: true
})

View File

@@ -2,11 +2,17 @@ machine:
node: node:
version: stable version: stable
post:
test:
- npm run coverage -- --upload
dependencies: dependencies:
pre: pre:
- google-chrome --version - google-chrome --version
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - - curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' - sudo dpkg -i google-chrome.deb || true
- sudo apt-get update - sudo apt-get update
- sudo apt-get --only-upgrade install google-chrome-stable - sudo apt-get install -f
- sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb
- google-chrome --version - google-chrome --version

View File

@@ -1,28 +1,25 @@
{ {
"name": "libp2p-crypto", "name": "libp2p-crypto",
"version": "0.7.2", "version": "0.10.4",
"description": "Crypto primitives for libp2p", "description": "Crypto primitives for libp2p",
"main": "src/index.js", "main": "src/index.js",
"browser": { "browser": {
"node-webcrypto-ossl": false, "./src/hmac/index.js": "./src/hmac/index-browser.js",
"./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js", "./src/keys/ecdh.js": "./src/keys/ecdh-browser.js",
"./src/crypto/hmac.js": "./src/crypto/hmac-browser.js", "./src/aes/ciphers.js": "./src/aes/ciphers-browser.js",
"./src/crypto/ecdh.js": "./src/crypto/ecdh-browser.js", "./src/keys/rsa.js": "./src/keys/rsa-browser.js"
"./src/crypto/ciphers.js": "./src/crypto/ciphers-browser.js",
"./src/crypto/rsa.js": "./src/crypto/rsa-browser.js"
}, },
"scripts": { "scripts": {
"lint": "aegir-lint", "lint": "aegir lint",
"build": "aegir-build", "build": "aegir build",
"test": "npm run test:node && npm run test:no-webcrypto && npm run test:browser", "build-proto": "pbjs --wrap commonjs --target static-module src/keys/keys.proto > src/keys/keys.proto.js",
"test:node": "aegir-test --env node", "test": "aegir test",
"test:no-webcrypto": "NO_WEBCRYPTO=true aegir-test --env node", "test:node": "aegir test -t node",
"test:browser": "aegir-test --env browser", "test:browser": "aegir test -t browser -t webworker",
"release": "aegir-release", "release": "aegir release",
"release-minor": "aegir-release --type minor", "release-minor": "aegir release --type minor",
"release-major": "aegir-release --type major", "release-major": "aegir release --type major",
"coverage": "aegir-coverage", "coverage": "aegir coverage --ignore src/keys/keys.proto.js"
"coverage-publish": "aegir-coverage publish"
}, },
"keywords": [ "keywords": [
"IPFS", "IPFS",
@@ -30,49 +27,55 @@
"crypto", "crypto",
"rsa" "rsa"
], ],
"author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>", "author": "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asn1.js": "^4.8.1", "asn1.js": "^5.0.0",
"async": "^2.1.2", "async": "^2.6.0",
"browserify-aes": "^1.0.6", "browserify-aes": "^1.1.1",
"keypair": "^1.0.0", "keypair": "^1.0.1",
"multihashing-async": "^0.3.0", "libp2p-crypto-secp256k1": "~0.2.2",
"nodeify": "^1.0.0", "multihashing-async": "~0.4.7",
"pem-jwk": "^1.5.1", "pem-jwk": "^1.5.1",
"protocol-buffers": "^3.2.1", "protons": "^1.0.0",
"rsa-pem-to-jwk": "^1.1.3", "rsa-pem-to-jwk": "^1.1.3",
"tweetnacl": "^1.0.0",
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master" "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
}, },
"devDependencies": { "devDependencies": {
"aegir": "^9.0.1", "aegir": "^12.2.0",
"benchmark": "^2.1.2", "benchmark": "^2.1.4",
"chai": "^3.5.0", "chai": "^4.1.2",
"pre-commit": "^1.1.3" "dirty-chai": "^2.0.1",
}, "pre-commit": "^1.2.2"
"optionalDependencies": {
"node-webcrypto-ossl": "^1.0.13"
}, },
"pre-commit": [ "pre-commit": [
"lint", "lint",
"test" "test"
], ],
"engines": { "engines": {
"node": ">=4.0.0" "node": ">=6.0.0",
"npm": ">=3.0.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/ipfs/js-libp2p-crypto.git" "url": "https://github.com/libp2p/js-libp2p-crypto.git"
}, },
"bugs": { "bugs": {
"url": "https://github.com/ipfs/js-libp2p-crypto/issues" "url": "https://github.com/libp2p/js-libp2p-crypto/issues"
}, },
"homepage": "https://github.com/ipfs/js-libp2p-crypto", "homepage": "https://github.com/libp2p/js-libp2p-crypto",
"contributors": [ "contributors": [
"David Dias <daviddias.p@gmail.com>", "David Dias <daviddias.p@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Greenkeeper <support@greenkeeper.io>",
"Jack Kleeman <jackkleeman@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>", "Richard Littauer <richard.littauer@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>", "Tom Swindell <t.swindell@rubyx.co.uk>",
"Yusef Napora <yusef@napora.org>",
"greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>",
"nikuda <nikuda@gmail.com>" "nikuda <nikuda@gmail.com>"
] ]
} }

55
src/aes/index-browser.js Normal file
View File

@@ -0,0 +1,55 @@
'use strict'
const asm = require('asmcrypto.js')
const setImmediate = require('async/setImmediate')
exports.create = function (key, iv, callback) {
const done = (err, res) => setImmediate(() => callback(err, res))
if (key.length !== 16 && key.length !== 32) {
return done(new Error('Invalid key length'))
}
const enc = new asm.AES_CTR.Encrypt({
key: key,
nonce: iv
})
const dec = new asm.AES_CTR.Decrypt({
key: key,
nonce: iv
})
const res = {
encrypt (data, cb) {
const done = (err, res) => setImmediate(() => cb(err, res))
let res
try {
res = Buffer.from(
enc.process(data).result
)
} catch (err) {
return done(err)
}
done(null, res)
},
decrypt (data, cb) {
const done = (err, res) => setImmediate(() => cb(err, res))
let res
try {
res = Buffer.from(
dec.process(data).result
)
} catch (err) {
return done(err)
}
done(null, res)
}
}
done(null, res)
}

View File

@@ -1,7 +0,0 @@
'use strict'
exports.webcrypto = require('./crypto/webcrypto')()
exports.hmac = require('./crypto/hmac')
exports.ecdh = require('./crypto/ecdh')
exports.aes = require('./crypto/aes')
exports.rsa = require('./crypto/rsa')

View File

@@ -1,80 +0,0 @@
'use strict'
// Node.js land
// First we look if node-webrypto-ossl is available
// otherwise we fall back to using keypair + node core
let webcrypto
try {
webcrypto = require('node-webcrypto-ossl')
} catch (err) {
// not available, use the code below
}
if (webcrypto && !process.env.NO_WEBCRYPTO) {
module.exports = require('./rsa-browser')
} else {
const crypto = require('crypto')
const keypair = require('keypair')
const setImmediate = require('async/setImmediate')
const pemToJwk = require('pem-jwk').pem2jwk
const jwkToPem = require('pem-jwk').jwk2pem
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
const done = (err, res) => setImmediate(() => {
callback(err, res)
})
let key
try {
key = keypair({
bits: bits
})
} catch (err) {
done(err)
return
}
done(null, {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
})
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
})
}
exports.getRandomValues = function (arr) {
return crypto.randomBytes(arr.length)
}
exports.hashAndSign = function (key, msg, callback) {
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
setImmediate(() => {
callback(null, sign.sign(jwkToPem(key)))
})
}
exports.hashAndVerify = function (key, sig, msg, callback) {
const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
setImmediate(() => {
callback(null, verify.verify(jwkToPem(key), sig))
})
}
}

View File

@@ -1,14 +0,0 @@
'use strict'
module.exports = function getWebCrypto () {
if (typeof window !== 'undefined') {
// This is only a shim for interfaces, not for functionality
require('webcrypto-shim')(window)
if (window.crypto) {
return window.crypto
}
}
throw new Error('Please use an environment with crypto support')
}

View File

@@ -1,11 +0,0 @@
'use strict'
module.exports = function getWebCrypto () {
try {
const WebCrypto = require('node-webcrypto-ossl')
const webCrypto = new WebCrypto()
return webCrypto
} catch (err) {
// fallback to other things
}
}

View File

@@ -1,9 +1,9 @@
'use strict' 'use strict'
const nodeify = require('nodeify') const nodeify = require('../nodeify')
const crypto = require('./webcrypto')() const crypto = require('../webcrypto.js')()
const lengths = require('./hmac-lengths') const lengths = require('./lengths')
const hashTypes = { const hashTypes = {
SHA1: 'SHA-1', SHA1: 'SHA-1',
@@ -11,6 +11,11 @@ const hashTypes = {
SHA512: 'SHA-512' SHA512: 'SHA-512'
} }
const sign = (key, data, cb) => {
nodeify(crypto.subtle.sign({name: 'HMAC'}, key, data)
.then((raw) => Buffer.from(raw)), cb)
}
exports.create = function (hashType, secret, callback) { exports.create = function (hashType, secret, callback) {
const hash = hashTypes[hashType] const hash = hashTypes[hashType]
@@ -26,11 +31,7 @@ exports.create = function (hashType, secret, callback) {
).then((key) => { ).then((key) => {
return { return {
digest (data, cb) { digest (data, cb) {
nodeify(crypto.subtle.sign( sign(key, data, cb)
{name: 'HMAC'},
key,
data
).then((raw) => Buffer.from(raw)), cb)
}, },
length: lengths[hashType] length: lengths[hashType]
} }

View File

@@ -1,13 +1,13 @@
'use strict' 'use strict'
const crypto = require('crypto') const crypto = require('crypto')
const lengths = require('./lengths')
const lengths = require('./hmac-lengths')
exports.create = function (hash, secret, callback) { exports.create = function (hash, secret, callback) {
const res = { const res = {
digest (data, cb) { digest (data, cb) {
const hmac = genFresh() const hmac = crypto.createHmac(hash.toLowerCase(), secret)
hmac.update(data) hmac.update(data)
setImmediate(() => { setImmediate(() => {
@@ -17,8 +17,5 @@ exports.create = function (hash, secret, callback) {
length: lengths[hash] length: lengths[hash]
} }
function genFresh () {
return crypto.createHmac(hash.toLowerCase(), secret)
}
callback(null, res) callback(null, res)
} }

View File

@@ -1,73 +1,12 @@
'use strict' 'use strict'
const protobuf = require('protocol-buffers') const hmac = require('./hmac')
const pbm = protobuf(require('./crypto.proto')) const aes = require('./aes')
const c = require('./crypto') const keys = require('./keys')
exports.hmac = c.hmac exports = module.exports
exports.aes = c.aes
exports.webcrypto = c.webcrypto
const keys = exports.keys = require('./keys') exports.aes = aes
exports.keyStretcher = require('./key-stretcher') exports.hmac = hmac
exports.generateEphemeralKeyPair = require('./ephemeral-keys') exports.keys = keys
exports.randomBytes = require('./random-bytes')
// Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits, cb) => {
let key = keys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
}
key.generateKeyPair(bits, cb)
}
// Converts a protobuf serialized public key into its
// representative object
exports.unmarshalPublicKey = (buf) => {
const decoded = pbm.PublicKey.decode(buf)
switch (decoded.Type) {
case pbm.KeyType.RSA:
return keys.rsa.unmarshalRsaPublicKey(decoded.Data)
default:
throw new Error('invalid or unsupported key type')
}
}
// Converts a public key object into a protobuf serialized public key
exports.marshalPublicKey = (key, type) => {
type = (type || 'rsa').toLowerCase()
// for now only rsa is supported
if (type !== 'rsa') {
throw new Error('invalid or unsupported key type')
}
return key.bytes
}
// Converts a protobuf serialized private key into its
// representative object
exports.unmarshalPrivateKey = (buf, callback) => {
const decoded = pbm.PrivateKey.decode(buf)
switch (decoded.Type) {
case pbm.KeyType.RSA:
return keys.rsa.unmarshalRsaPrivateKey(decoded.Data, callback)
default:
callback(new Error('invalid or unsupported key type'))
}
}
// Converts a private key object into a protobuf serialized private key
exports.marshalPrivateKey = (key, type) => {
type = (type || 'rsa').toLowerCase()
// for now only rsa is supported
if (type !== 'rsa') {
throw new Error('invalid or unsupported key type')
}
return key.bytes
}

View File

@@ -1,10 +1,10 @@
'use strict' 'use strict'
const crypto = require('./webcrypto')() const webcrypto = require('../webcrypto.js')()
const nodeify = require('nodeify') const nodeify = require('../nodeify')
const BN = require('asn1.js').bignum const BN = require('asn1.js').bignum
const util = require('./util') const util = require('../util')
const toBase64 = util.toBase64 const toBase64 = util.toBase64
const toBn = util.toBn const toBn = util.toBn
@@ -15,7 +15,7 @@ const bits = {
} }
exports.generateEphmeralKeyPair = function (curve, callback) { exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(crypto.subtle.generateKey( nodeify(webcrypto.subtle.generateKey(
{ {
name: 'ECDH', name: 'ECDH',
namedCurve: curve namedCurve: curve
@@ -33,7 +33,7 @@ exports.generateEphmeralKeyPair = function (curve, callback) {
let privateKey let privateKey
if (forcePrivate) { if (forcePrivate) {
privateKey = crypto.subtle.importKey( privateKey = webcrypto.subtle.importKey(
'jwk', 'jwk',
unmarshalPrivateKey(curve, forcePrivate), unmarshalPrivateKey(curve, forcePrivate),
{ {
@@ -48,7 +48,7 @@ exports.generateEphmeralKeyPair = function (curve, callback) {
} }
const keys = Promise.all([ const keys = Promise.all([
crypto.subtle.importKey( webcrypto.subtle.importKey(
'jwk', 'jwk',
unmarshalPublicKey(curve, theirPub), unmarshalPublicKey(curve, theirPub),
{ {
@@ -61,7 +61,7 @@ exports.generateEphmeralKeyPair = function (curve, callback) {
privateKey privateKey
]) ])
nodeify(keys.then((keys) => crypto.subtle.deriveBits( nodeify(keys.then((keys) => webcrypto.subtle.deriveBits(
{ {
name: 'ECDH', name: 'ECDH',
namedCurve: curve, namedCurve: curve,
@@ -72,15 +72,13 @@ exports.generateEphmeralKeyPair = function (curve, callback) {
)).then((bits) => Buffer.from(bits)), cb) )).then((bits) => Buffer.from(bits)), cb)
} }
return crypto.subtle.exportKey( return webcrypto.subtle.exportKey('jwk', pair.publicKey)
'jwk', .then((publicKey) => {
pair.publicKey return {
).then((publicKey) => { key: marshalPublicKey(publicKey),
return { genSharedKey
key: marshalPublicKey(publicKey), }
genSharedKey })
}
})
}), callback) }), callback)
} }
@@ -97,9 +95,9 @@ function marshalPublicKey (jwk) {
const byteLen = curveLengths[jwk.crv] const byteLen = curveLengths[jwk.crv]
return Buffer.concat([ return Buffer.concat([
new Buffer([4]), // uncompressed point Buffer.from([4]), // uncompressed point
toBn(jwk.x).toBuffer('be', byteLen), toBn(jwk.x).toArrayLike(Buffer, 'be', byteLen),
toBn(jwk.y).toBuffer('be', byteLen) toBn(jwk.y).toArrayLike(Buffer, 'be', byteLen)
], 1 + byteLen * 2) ], 1 + byteLen * 2)
} }
@@ -107,7 +105,7 @@ function marshalPublicKey (jwk) {
function unmarshalPublicKey (curve, key) { function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve] const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(new Buffer([4]))) { if (!key.slice(0, 1).equals(Buffer.from([4]))) {
throw new Error('Invalid key format') throw new Error('Invalid key format')
} }
const x = new BN(key.slice(1, byteLen + 1)) const x = new BN(key.slice(1, byteLen + 1))
@@ -116,8 +114,8 @@ function unmarshalPublicKey (curve, key) {
return { return {
kty: 'EC', kty: 'EC',
crv: curve, crv: curve,
x: toBase64(x), x: toBase64(x, byteLen),
y: toBase64(y), y: toBase64(y, byteLen),
ext: true ext: true
} }
} }

163
src/keys/ed25519-class.js Normal file
View File

@@ -0,0 +1,163 @@
'use strict'
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const crypto = require('./ed25519')
const pbm = protobuf(require('./keys.proto'))
class Ed25519PublicKey {
constructor (key) {
this._key = ensureKey(key, crypto.publicKeyLength)
}
verify (data, sig, callback) {
ensure(callback)
crypto.hashAndVerify(this._key, sig, data, callback)
}
marshal () {
return Buffer.from(this._key)
}
get bytes () {
return pbm.PublicKey.encode({
Type: pbm.KeyType.Ed25519,
Data: this.marshal()
})
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
}
class Ed25519PrivateKey {
// key - 64 byte Uint8Array or Buffer containing private key
// publicKey - 32 byte Uint8Array or Buffer containing public key
constructor (key, publicKey) {
this._key = ensureKey(key, crypto.privateKeyLength)
this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
}
sign (message, callback) {
ensure(callback)
crypto.hashAndSign(this._key, message, callback)
}
get public () {
if (!this._publicKey) {
throw new Error('public key not provided')
}
return new Ed25519PublicKey(this._publicKey)
}
marshal () {
return Buffer.concat([Buffer.from(this._key), Buffer.from(this._publicKey)])
}
get bytes () {
return pbm.PrivateKey.encode({
Type: pbm.KeyType.Ed25519,
Data: this.marshal()
})
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
}
function unmarshalEd25519PrivateKey (bytes, callback) {
try {
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
} catch (err) {
return callback(err)
}
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
callback(null, new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes))
}
function unmarshalEd25519PublicKey (bytes) {
bytes = ensureKey(bytes, crypto.publicKeyLength)
return new Ed25519PublicKey(bytes)
}
function generateKeyPair (_bits, cb) {
if (cb === undefined && typeof _bits === 'function') {
cb = _bits
}
crypto.generateKey((err, keys) => {
if (err) {
return cb(err)
}
let privkey
try {
privkey = new Ed25519PrivateKey(keys.secretKey, keys.publicKey)
} catch (err) {
cb(err)
return
}
cb(null, privkey)
})
}
function generateKeyPairFromSeed (seed, _bits, cb) {
if (cb === undefined && typeof _bits === 'function') {
cb = _bits
}
crypto.generateKeyFromSeed(seed, (err, keys) => {
if (err) {
return cb(err)
}
let privkey
try {
privkey = new Ed25519PrivateKey(keys.secretKey, keys.publicKey)
} catch (err) {
cb(err)
return
}
cb(null, privkey)
})
}
function ensure (cb) {
if (typeof cb !== 'function') {
throw new Error('callback is required')
}
}
function ensureKey (key, length) {
if (Buffer.isBuffer(key)) {
key = new Uint8Array(key)
}
if (!(key instanceof Uint8Array) || key.length !== length) {
throw new Error('Key must be a Uint8Array or Buffer of length ' + length)
}
return key
}
module.exports = {
Ed25519PublicKey,
Ed25519PrivateKey,
unmarshalEd25519PrivateKey,
unmarshalEd25519PublicKey,
generateKeyPair,
generateKeyPairFromSeed
}

51
src/keys/ed25519.js Normal file
View File

@@ -0,0 +1,51 @@
'use strict'
const nacl = require('tweetnacl')
const setImmediate = require('async/setImmediate')
exports.publicKeyLength = nacl.sign.publicKeyLength
exports.privateKeyLength = nacl.sign.secretKeyLength
exports.generateKey = function (callback) {
setImmediate(() => {
let result
try {
result = nacl.sign.keyPair()
} catch (err) {
return callback(err)
}
callback(null, result)
})
}
// seed should be a 32 byte uint8array
exports.generateKeyFromSeed = function (seed, callback) {
setImmediate(() => {
let result
try {
result = nacl.sign.keyPair.fromSeed(seed)
} catch (err) {
return callback(err)
}
callback(null, result)
})
}
exports.hashAndSign = function (key, msg, callback) {
setImmediate(() => {
callback(null, Buffer.from(nacl.sign.detached(msg, key)))
})
}
exports.hashAndVerify = function (key, sig, msg, callback) {
setImmediate(() => {
let result
try {
result = nacl.sign.detached.verify(msg, sig, key)
} catch (err) {
return callback(err)
}
callback(null, result)
})
}

View File

@@ -1,11 +1,11 @@
'use strict' 'use strict'
const crypto = require('./crypto') const ecdh = require('./ecdh')
// Generates an ephemeral public key and returns a function that will compute // Generates an ephemeral public key and returns a function that will compute
// the shared secret key. // the shared secret key.
// //
// Focuses only on ECDH now, but can be made more general in the future. // Focuses only on ECDH now, but can be made more general in the future.
module.exports = (curve, callback) => { module.exports = (curve, callback) => {
crypto.ecdh.generateEphmeralKeyPair(curve, callback) ecdh.generateEphmeralKeyPair(curve, callback)
} }

View File

@@ -1,5 +1,117 @@
'use strict' 'use strict'
module.exports = { const protobuf = require('protons')
rsa: require('./rsa') const keysPBM = protobuf(require('./keys.proto'))
exports = module.exports
const supportedKeys = {
rsa: require('./rsa-class'),
ed25519: require('./ed25519-class'),
secp256k1: require('libp2p-crypto-secp256k1')(keysPBM, require('../random-bytes'))
}
exports.supportedKeys = supportedKeys
exports.keysPBM = keysPBM
function isValidKeyType (keyType) {
const key = supportedKeys[keyType.toLowerCase()]
return key !== undefined
}
exports.keyStretcher = require('./key-stretcher')
exports.generateEphemeralKeyPair = require('./ephemeral-keys')
// Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits, cb) => {
let key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
}
key.generateKeyPair(bits, cb)
}
// Generates a keypair of the given type and bitsize
// seed is a 32 byte uint8array
exports.generateKeyPairFromSeed = (type, seed, bits, cb) => {
let key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
}
if (type.toLowerCase() !== 'ed25519') {
return cb(new Error('Seed key derivation is unimplemented for RSA or secp256k1'))
}
key.generateKeyPairFromSeed(seed, bits, cb)
}
// Converts a protobuf serialized public key into its
// representative object
exports.unmarshalPublicKey = (buf) => {
const decoded = keysPBM.PublicKey.decode(buf)
const data = decoded.Data
switch (decoded.Type) {
case keysPBM.KeyType.RSA:
return supportedKeys.rsa.unmarshalRsaPublicKey(data)
case keysPBM.KeyType.Ed25519:
return supportedKeys.ed25519.unmarshalEd25519PublicKey(data)
case keysPBM.KeyType.Secp256k1:
if (supportedKeys.secp256k1) {
return supportedKeys.secp256k1.unmarshalSecp256k1PublicKey(data)
} else {
throw new Error('secp256k1 support requires libp2p-crypto-secp256k1 package')
}
default:
throw new Error('invalid or unsupported key type')
}
}
// Converts a public key object into a protobuf serialized public key
exports.marshalPublicKey = (key, type) => {
type = (type || 'rsa').toLowerCase()
if (!isValidKeyType(type)) {
throw new Error('invalid or unsupported key type')
}
return key.bytes
}
// Converts a protobuf serialized private key into its
// representative object
exports.unmarshalPrivateKey = (buf, callback) => {
let decoded
try {
decoded = keysPBM.PrivateKey.decode(buf)
} catch (err) {
return callback(err)
}
const data = decoded.Data
switch (decoded.Type) {
case keysPBM.KeyType.RSA:
return supportedKeys.rsa.unmarshalRsaPrivateKey(data, callback)
case keysPBM.KeyType.Ed25519:
return supportedKeys.ed25519.unmarshalEd25519PrivateKey(data, callback)
case keysPBM.KeyType.Secp256k1:
if (supportedKeys.secp256k1) {
return supportedKeys.secp256k1.unmarshalSecp256k1PrivateKey(data, callback)
} else {
return callback(new Error('secp256k1 support requires libp2p-crypto-secp256k1 package'))
}
default:
callback(new Error('invalid or unsupported key type'))
}
}
// Converts a private key object into a protobuf serialized private key
exports.marshalPrivateKey = (key, type) => {
type = (type || 'rsa').toLowerCase()
if (!isValidKeyType(type)) {
throw new Error('invalid or unsupported key type')
}
return key.bytes
} }

View File

@@ -1,7 +1,7 @@
'use strict' 'use strict'
const crypto = require('./crypto')
const whilst = require('async/whilst') const whilst = require('async/whilst')
const hmac = require('../hmac')
const cipherMap = { const cipherMap = {
'AES-128': { 'AES-128': {
@@ -37,7 +37,7 @@ module.exports = (cipherType, hash, secret, callback) => {
const seed = Buffer.from('key expansion') const seed = Buffer.from('key expansion')
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize) const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
crypto.hmac.create(hash, secret, (err, m) => { hmac.create(hash, secret, (err, m) => {
if (err) { if (err) {
return callback(err) return callback(err)
} }

View File

@@ -2,14 +2,14 @@
module.exports = `enum KeyType { module.exports = `enum KeyType {
RSA = 0; RSA = 0;
Ed25519 = 1;
Secp256k1 = 2;
} }
message PublicKey { message PublicKey {
required KeyType Type = 1; required KeyType Type = 1;
required bytes Data = 2; required bytes Data = 2;
} }
message PrivateKey { message PrivateKey {
required KeyType Type = 1; required KeyType Type = 1;
required bytes Data = 2; required bytes Data = 2;
}` }`

View File

@@ -1,13 +1,13 @@
'use strict' 'use strict'
const nodeify = require('nodeify') const nodeify = require('../nodeify')
const crypto = require('./webcrypto')() const webcrypto = require('../webcrypto.js')()
exports.utils = require('./rsa-utils') exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) { exports.generateKey = function (bits, callback) {
nodeify(crypto.subtle.generateKey( nodeify(webcrypto.subtle.generateKey(
{ {
name: 'RSASSA-PKCS1-v1_5', name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits, modulusLength: bits,
@@ -17,16 +17,16 @@ exports.generateKey = function (bits, callback) {
true, true,
['sign', 'verify'] ['sign', 'verify']
) )
.then(exportKey) .then(exportKey)
.then((keys) => ({ .then((keys) => ({
privateKey: keys[0], privateKey: keys[0],
publicKey: keys[1] publicKey: keys[1]
})), callback) })), callback)
} }
// Takes a jwk key // Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) { exports.unmarshalPrivateKey = function (key, callback) {
const privateKey = crypto.subtle.importKey( const privateKey = webcrypto.subtle.importKey(
'jwk', 'jwk',
key, key,
{ {
@@ -50,11 +50,11 @@ exports.unmarshalPrivateKey = function (key, callback) {
} }
exports.getRandomValues = function (arr) { exports.getRandomValues = function (arr) {
return Buffer.from(crypto.getRandomValues(arr)) return Buffer.from(webcrypto.getRandomValues(arr))
} }
exports.hashAndSign = function (key, msg, callback) { exports.hashAndSign = function (key, msg, callback) {
nodeify(crypto.subtle.importKey( nodeify(webcrypto.subtle.importKey(
'jwk', 'jwk',
key, key,
{ {
@@ -64,7 +64,7 @@ exports.hashAndSign = function (key, msg, callback) {
false, false,
['sign'] ['sign']
).then((privateKey) => { ).then((privateKey) => {
return crypto.subtle.sign( return webcrypto.subtle.sign(
{name: 'RSASSA-PKCS1-v1_5'}, {name: 'RSASSA-PKCS1-v1_5'},
privateKey, privateKey,
Uint8Array.from(msg) Uint8Array.from(msg)
@@ -73,7 +73,7 @@ exports.hashAndSign = function (key, msg, callback) {
} }
exports.hashAndVerify = function (key, sig, msg, callback) { exports.hashAndVerify = function (key, sig, msg, callback) {
nodeify(crypto.subtle.importKey( nodeify(webcrypto.subtle.importKey(
'jwk', 'jwk',
key, key,
{ {
@@ -83,7 +83,7 @@ exports.hashAndVerify = function (key, sig, msg, callback) {
false, false,
['verify'] ['verify']
).then((publicKey) => { ).then((publicKey) => {
return crypto.subtle.verify( return webcrypto.subtle.verify(
{name: 'RSASSA-PKCS1-v1_5'}, {name: 'RSASSA-PKCS1-v1_5'},
publicKey, publicKey,
sig, sig,
@@ -94,13 +94,13 @@ exports.hashAndVerify = function (key, sig, msg, callback) {
function exportKey (pair) { function exportKey (pair) {
return Promise.all([ return Promise.all([
crypto.subtle.exportKey('jwk', pair.privateKey), webcrypto.subtle.exportKey('jwk', pair.privateKey),
crypto.subtle.exportKey('jwk', pair.publicKey) webcrypto.subtle.exportKey('jwk', pair.publicKey)
]) ])
} }
function derivePublicFromPrivate (jwKey) { function derivePublicFromPrivate (jwKey) {
return crypto.subtle.importKey( return webcrypto.subtle.importKey(
'jwk', 'jwk',
{ {
kty: jwKey.kty, kty: jwKey.kty,

133
src/keys/rsa-class.js Normal file
View File

@@ -0,0 +1,133 @@
'use strict'
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
class RsaPublicKey {
constructor (key) {
this._key = key
}
verify (data, sig, callback) {
ensure(callback)
crypto.hashAndVerify(this._key, sig, data, callback)
}
marshal () {
return crypto.utils.jwkToPkix(this._key)
}
get bytes () {
return pbm.PublicKey.encode({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
encrypt (bytes) {
return this._key.encrypt(bytes, 'RSAES-PKCS1-V1_5')
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
}
class RsaPrivateKey {
// key - Object of the jwk format
// publicKey - Buffer of the spki format
constructor (key, publicKey) {
this._key = key
this._publicKey = publicKey
}
genSecret () {
return crypto.getRandomValues(new Uint8Array(16))
}
sign (message, callback) {
ensure(callback)
crypto.hashAndSign(this._key, message, callback)
}
get public () {
if (!this._publicKey) {
throw new Error('public key not provided')
}
return new RsaPublicKey(this._publicKey)
}
decrypt (msg, callback) {
crypto.decrypt(this._key, msg, callback)
}
marshal () {
return crypto.utils.jwkToPkcs1(this._key)
}
get bytes () {
return pbm.PrivateKey.encode({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
}
function unmarshalRsaPrivateKey (bytes, callback) {
const jwk = crypto.utils.pkcs1ToJwk(bytes)
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
}
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
}
function unmarshalRsaPublicKey (bytes) {
const jwk = crypto.utils.pkixToJwk(bytes)
return new RsaPublicKey(jwk)
}
function generateKeyPair (bits, cb) {
crypto.generateKey(bits, (err, keys) => {
if (err) {
return cb(err)
}
cb(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
}
function ensure (cb) {
if (typeof cb !== 'function') {
throw new Error('callback is required')
}
}
module.exports = {
RsaPublicKey,
RsaPrivateKey,
unmarshalRsaPublicKey,
unmarshalRsaPrivateKey,
generateKeyPair
}

View File

@@ -2,7 +2,7 @@
const asn1 = require('asn1.js') const asn1 = require('asn1.js')
const util = require('./util') const util = require('./../util')
const toBase64 = util.toBase64 const toBase64 = util.toBase64
const toBn = util.toBn const toBn = util.toBn

View File

@@ -1,133 +1,79 @@
'use strict' 'use strict'
const multihashing = require('multihashing-async') const crypto = require('crypto')
const protobuf = require('protocol-buffers') const keypair = require('keypair')
const setImmediate = require('async/setImmediate')
const pemToJwk = require('pem-jwk').pem2jwk
const jwkToPem = require('pem-jwk').jwk2pem
const crypto = require('../crypto').rsa exports.utils = require('./rsa-utils')
const pbm = protobuf(require('../crypto.proto'))
class RsaPublicKey { exports.generateKey = function (bits, callback) {
constructor (key) { setImmediate(() => {
this._key = key let result
} try {
const key = keypair({ bits: bits })
verify (data, sig, callback) { result = {
ensure(callback) privateKey: pemToJwk(key.private),
crypto.hashAndVerify(this._key, sig, data, callback) publicKey: pemToJwk(key.public)
} }
} catch (err) {
marshal () {
return crypto.utils.jwkToPkix(this._key)
}
get bytes () {
return pbm.PublicKey.encode({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
encrypt (bytes) {
return this._key.encrypt(bytes, 'RSAES-PKCS1-V1_5')
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
}
class RsaPrivateKey {
// key - Object of the jwk format
// publicKey - Buffer of the spki format
constructor (key, publicKey) {
this._key = key
this._publicKey = publicKey
}
genSecret () {
return crypto.getRandomValues(new Uint8Array(16))
}
sign (message, callback) {
ensure(callback)
crypto.hashAndSign(this._key, message, callback)
}
get public () {
if (!this._publicKey) {
throw new Error('public key not provided')
}
return new RsaPublicKey(this._publicKey)
}
decrypt (msg, callback) {
crypto.decrypt(this._key, msg, callback)
}
marshal () {
return crypto.utils.jwkToPkcs1(this._key)
}
get bytes () {
return pbm.PrivateKey.encode({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
}
function unmarshalRsaPrivateKey (bytes, callback) {
const jwk = crypto.utils.pkcs1ToJwk(bytes)
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err) return callback(err)
} }
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey)) callback(null, result)
}) })
} }
function unmarshalRsaPublicKey (bytes) { // Takes a jwk key
const jwk = crypto.utils.pkixToJwk(bytes) exports.unmarshalPrivateKey = function (key, callback) {
setImmediate(() => {
return new RsaPublicKey(jwk) if (!key) {
return callback(new Error('Key is invalid'))
}
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
})
})
} }
function generateKeyPair (bits, cb) { exports.getRandomValues = function (arr) {
crypto.generateKey(bits, (err, keys) => { return crypto.randomBytes(arr.length)
if (err) { }
return cb(err)
exports.hashAndSign = function (key, msg, callback) {
setImmediate(() => {
let result
try {
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
const pem = jwkToPem(key)
result = sign.sign(pem)
} catch (err) {
return callback(new Error('Key or message is invalid!: ' + err.message))
} }
cb(null, new RsaPrivateKey(keys.privateKey, keys.publicKey)) callback(null, result)
}) })
} }
function ensure (cb) { exports.hashAndVerify = function (key, sig, msg, callback) {
if (typeof cb !== 'function') { setImmediate(() => {
throw new Error('callback is required') let result
} try {
} const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
const pem = jwkToPem(key)
result = verify.verify(pem, sig)
} catch (err) {
return callback(new Error('Key or message is invalid!:' + err.message))
}
module.exports = { callback(null, result)
RsaPublicKey, })
RsaPrivateKey,
unmarshalRsaPublicKey,
unmarshalRsaPrivateKey,
generateKeyPair
} }

11
src/nodeify.js Normal file
View File

@@ -0,0 +1,11 @@
'use strict'
// Based on npmjs.com/nodeify but without additional `nextTick` calls
// to keep the overhead low
module.exports = function nodeify (promise, cb) {
return promise.then((res) => {
cb(null, res)
}, (err) => {
cb(err)
})
}

13
src/random-bytes.js Normal file
View File

@@ -0,0 +1,13 @@
'use strict'
const rsa = require('./keys/rsa')
function randomBytes (number) {
if (!number || typeof number !== 'number') {
throw new Error('first argument must be a Number bigger than 0')
}
return rsa.getRandomValues(new Uint8Array(number))
}
module.exports = randomBytes

View File

@@ -4,13 +4,14 @@ const BN = require('asn1.js').bignum
// Convert a BN.js instance to a base64 encoded string without padding // 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 // Adapted from https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#appendix-C
exports.toBase64 = function toBase64 (bn) { exports.toBase64 = function toBase64 (bn, len) {
let s = bn.toBuffer('be').toString('base64') // if len is defined then the bytes are leading-0 padded to the length
let s = bn.toArrayLike(Buffer, 'be', len).toString('base64')
return s return s
.replace(/(=*)$/, '') // Remove any trailing '='s .replace(/(=*)$/, '') // Remove any trailing '='s
.replace(/\+/g, '-') // 62nd char of encoding .replace(/\+/g, '-') // 62nd char of encoding
.replace(/\//g, '_') // 63rd char of encoding .replace(/\//g, '_') // 63rd char of encoding
} }
// Convert a base64 encoded string to a BN.js instance // Convert a base64 encoded string to a BN.js instance

16
src/webcrypto.js Normal file
View File

@@ -0,0 +1,16 @@
/* global self */
'use strict'
module.exports = () => {
// This is only a shim for interfaces, not for functionality
if (typeof self !== 'undefined') {
require('webcrypto-shim')(self)
if (self.crypto) {
return self.crypto
}
}
throw new Error('Please use an environment with crypto support')
}

View File

@@ -2,12 +2,15 @@
/* eslint-env mocha */ /* eslint-env mocha */
'use strict' 'use strict'
const expect = require('chai').expect const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const series = require('async/series') const series = require('async/series')
const crypto = require('../src') const crypto = require('../../src')
const fixtures = require('./fixtures/aes') const fixtures = require('./../fixtures/aes')
const goFixtures = require('./fixtures/go-aes') const goFixtures = require('./../fixtures/go-aes')
const bytes = { const bytes = {
16: 'AES-128', 16: 'AES-128',
@@ -17,14 +20,14 @@ const bytes = {
describe('AES-CTR', () => { describe('AES-CTR', () => {
Object.keys(bytes).forEach((byte) => { Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - encrypt and decrypt`, (done) => { it(`${bytes[byte]} - encrypt and decrypt`, (done) => {
const key = new Buffer(parseInt(byte, 10)) const key = Buffer.alloc(parseInt(byte, 10))
key.fill(5) key.fill(5)
const iv = new Buffer(16) const iv = Buffer.alloc(16)
iv.fill(1) iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => { crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist expect(err).to.not.exist()
series([ series([
encryptAndDecrypt(cipher), encryptAndDecrypt(cipher),
@@ -36,27 +39,28 @@ describe('AES-CTR', () => {
}) })
}) })
}) })
Object.keys(bytes).forEach((byte) => { Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - fixed - encrypt and decrypt`, (done) => { it(`${bytes[byte]} - fixed - encrypt and decrypt`, (done) => {
const key = new Buffer(parseInt(byte, 10)) const key = Buffer.alloc(parseInt(byte, 10))
key.fill(5) key.fill(5)
const iv = new Buffer(16) const iv = Buffer.alloc(16)
iv.fill(1) iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => { crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist expect(err).to.not.exist()
series(fixtures[byte].inputs.map((rawIn, i) => (cb) => { series(fixtures[byte].inputs.map((rawIn, i) => (cb) => {
const input = new Buffer(rawIn) const input = Buffer.from(rawIn)
const output = new Buffer(fixtures[byte].outputs[i]) const output = Buffer.from(fixtures[byte].outputs[i])
cipher.encrypt(input, (err, res) => { cipher.encrypt(input, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(res).to.have.length(output.length) expect(res).to.have.length(output.length)
expect(res).to.be.eql(output) expect(res).to.eql(output)
cipher.decrypt(res, (err, res) => { cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(res).to.be.eql(input) expect(res).to.eql(input)
cb() cb()
}) })
}) })
@@ -71,24 +75,24 @@ describe('AES-CTR', () => {
} }
it(`${bytes[byte]} - go interop - encrypt and decrypt`, (done) => { it(`${bytes[byte]} - go interop - encrypt and decrypt`, (done) => {
const key = new Buffer(parseInt(byte, 10)) const key = Buffer.alloc(parseInt(byte, 10))
key.fill(5) key.fill(5)
const iv = new Buffer(16) const iv = Buffer.alloc(16)
iv.fill(1) iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => { crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist expect(err).to.not.exist()
series(goFixtures[byte].inputs.map((rawIn, i) => (cb) => { series(goFixtures[byte].inputs.map((rawIn, i) => (cb) => {
const input = new Buffer(rawIn) const input = Buffer.from(rawIn)
const output = new Buffer(goFixtures[byte].outputs[i]) const output = Buffer.from(goFixtures[byte].outputs[i])
cipher.encrypt(input, (err, res) => { cipher.encrypt(input, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(res).to.have.length(output.length) expect(res).to.have.length(output.length)
expect(res).to.be.eql(output) expect(res).to.be.eql(output)
cipher.decrypt(res, (err, res) => { cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(res).to.be.eql(input) expect(res).to.be.eql(input)
cb() cb()
}) })
@@ -100,13 +104,13 @@ describe('AES-CTR', () => {
}) })
function encryptAndDecrypt (cipher) { function encryptAndDecrypt (cipher) {
const data = new Buffer(100) const data = Buffer.alloc(100)
data.fill(Math.ceil(Math.random() * 100)) data.fill(Math.ceil(Math.random() * 100))
return (cb) => { return (cb) => {
cipher.encrypt(data, (err, res) => { cipher.encrypt(data, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
cipher.decrypt(res, (err, res) => { cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(res).to.be.eql(data) expect(res).to.be.eql(data)
cb() cb()
}) })

124
test/crypto.spec.js Normal file
View File

@@ -0,0 +1,124 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const crypto = require('../src')
const fixtures = require('./fixtures/go-key-rsa')
describe('libp2p-crypto', function () {
this.timeout(20 * 1000)
let key
before((done) => {
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) {
return done(err)
}
key = _key
done()
})
})
it('marshalPublicKey and unmarshalPublicKey', () => {
const key2 = crypto.keys.unmarshalPublicKey(
crypto.keys.marshalPublicKey(key.public))
expect(key2.equals(key.public)).to.be.eql(true)
expect(() => {
crypto.keys.marshalPublicKey(key.public, 'invalid-key-type')
}).to.throw()
})
it('marshalPrivateKey and unmarshalPrivateKey', (done) => {
expect(() => {
crypto.keys.marshalPrivateKey(key, 'invalid-key-type')
}).to.throw()
crypto.keys.unmarshalPrivateKey(crypto.keys.marshalPrivateKey(key), (err, key2) => {
if (err) {
return done(err)
}
expect(key2.equals(key)).to.be.eql(true)
expect(key2.public.equals(key.public)).to.be.eql(true)
done()
})
})
// marshalled keys seem to be slightly different
// unsure as to if this is just a difference in encoding
// or a bug
describe('go interop', () => {
it('unmarshals private key', (done) => {
crypto.keys.unmarshalPrivateKey(fixtures.private.key, (err, key) => {
if (err) {
return done(err)
}
const hash = fixtures.private.hash
expect(fixtures.private.key).to.eql(key.bytes)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.eql(hash)
done()
})
})
})
it('unmarshals public key', (done) => {
const key = crypto.keys.unmarshalPublicKey(fixtures.public.key)
const hash = fixtures.public.hash
expect(crypto.keys.marshalPublicKey(key)).to.eql(fixtures.public.key)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.eql(hash)
done()
})
})
it('unmarshal -> marshal, private key', (done) => {
crypto.keys.unmarshalPrivateKey(fixtures.private.key, (err, key) => {
if (err) {
return done(err)
}
const marshalled = crypto.keys.marshalPrivateKey(key)
expect(marshalled).to.eql(fixtures.private.key)
done()
})
})
it('unmarshal -> marshal, public key', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.public.key)
const marshalled = crypto.keys.marshalPublicKey(key)
expect(fixtures.public.key.equals(marshalled)).to.eql(true)
})
})
describe('randomBytes', () => {
it('throws with no number passed', () => {
expect(() => {
crypto.randomBytes()
}).to.throw()
})
it('generates different random things', () => {
const buf1 = crypto.randomBytes(10)
expect(buf1.length).to.equal(10)
const buf2 = crypto.randomBytes(10)
expect(buf1).to.not.eql(buf2)
})
})
})

View File

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

28
test/fixtures/go-key-ed25519.js vendored Normal file
View File

@@ -0,0 +1,28 @@
'use strict'
module.exports = {
// These were generated in a gore (https://github.com/motemen/gore) repl session:
//
// :import github.com/libp2p/go-libp2p-crypto
// :import crypto/rand
// priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
// pubkeyBytes, err := pub.Bytes()
// privkeyBytes, err := priv.Bytes()
// data := []byte("hello! and welcome to some awesome crypto primitives")
// sig, err := priv.Sign(data)
//
// :import io/ioutil
// ioutil.WriteFile("/tmp/pubkey_go.bin", pubkeyBytes, 0644)
// // etc..
//
// Then loaded into a node repl and dumped to arrays with:
//
// var pubkey = Array.from(fs.readFileSync('/tmp/pubkey_go.bin'))
// console.log(JSON.stringify(pubkey))
verify: {
privateKey: Buffer.from([8, 1, 18, 96, 201, 208, 1, 110, 176, 16, 230, 37, 66, 184, 149, 252, 78, 56, 206, 136, 2, 38, 118, 152, 226, 197, 117, 200, 54, 189, 156, 218, 184, 7, 118, 57, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37]),
publicKey: Buffer.from([8, 1, 18, 32, 233, 49, 221, 97, 164, 158, 241, 129, 73, 166, 225, 255, 193, 118, 22, 84, 55, 15, 249, 168, 225, 180, 198, 191, 14, 75, 187, 243, 150, 91, 232, 37]),
data: Buffer.from([104, 101, 108, 108, 111, 33, 32, 97, 110, 100, 32, 119, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 115, 111, 109, 101, 32, 97, 119, 101, 115, 111, 109, 101, 32, 99, 114, 121, 112, 116, 111, 32, 112, 114, 105, 109, 105, 116, 105, 118, 101, 115]),
signature: Buffer.from([7, 230, 175, 164, 228, 58, 78, 208, 62, 243, 73, 142, 83, 195, 176, 217, 166, 62, 41, 165, 168, 164, 75, 179, 163, 86, 102, 32, 18, 84, 150, 237, 39, 207, 213, 20, 134, 237, 50, 41, 176, 183, 229, 133, 38, 255, 42, 228, 68, 186, 100, 14, 175, 156, 243, 118, 125, 125, 120, 212, 124, 103, 252, 12])
}
}

View File

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

View File

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

8
test/fixtures/secp256k1.js vendored Normal file
View File

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

View File

@@ -0,0 +1,46 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const util = require('util')
const garbage = [Buffer.from('00010203040506070809', 'hex'), {}, null, false, undefined, true, 1, 0, Buffer.from(''), 'aGVsbG93b3JsZA==', 'helloworld', '']
function doTests (fncName, fnc, num, skipBuffersAndStrings) {
if (!num) {
num = 1
}
garbage.forEach((garbage) => {
if (skipBuffersAndStrings && (Buffer.isBuffer(garbage) || (typeof garbage) === 'string')) {
// skip this garbage because it's a buffer or a string and we were told do do that
return
}
let args = []
for (let i = 0; i < num; i++) {
args.push(garbage)
}
it(fncName + '(' + args.map(garbage => util.inspect(garbage)).join(', ') + ')', cb => {
args.push((err, res) => {
expect(err).to.exist()
expect(res).to.not.exist()
cb()
})
fnc.apply(null, args)
})
})
}
module.exports = (obj, fncs, num) => {
describe('returns error via cb instead of crashing', () => {
fncs.forEach(fnc => {
doTests(fnc, obj[fnc], num)
})
})
}
module.exports.doTests = doTests

View File

@@ -1,24 +0,0 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const crypto = require('../src')
const hashes = ['SHA1', 'SHA256', 'SHA512']
describe('HMAC', () => {
hashes.forEach((hash) => {
it(`${hash} - sign and verify`, (done) => {
crypto.hmac.create(hash, new Buffer('secret'), (err, hmac) => {
expect(err).to.not.exist
hmac.digest(new Buffer('hello world'), (err, sig) => {
expect(err).to.not.exist
expect(sig).to.have.length(hmac.length)
done()
})
})
})
})
})

28
test/hmac/hmac.spec.js Normal file
View File

@@ -0,0 +1,28 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const crypto = require('../../src')
const hashes = ['SHA1', 'SHA256', 'SHA512']
describe('HMAC', () => {
hashes.forEach((hash) => {
it(`${hash} - sign and verify`, (done) => {
crypto.hmac.create(hash, Buffer.from('secret'), (err, hmac) => {
expect(err).to.not.exist()
hmac.digest(Buffer.from('hello world'), (err, sig) => {
expect(err).to.not.exist()
expect(sig).to.have.length(hmac.length)
done()
})
})
})
})
})

View File

@@ -1,101 +0,0 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const crypto = require('../src')
const fixtures = require('./fixtures/go-key-rsa')
describe('libp2p-crypto', () => {
let key
before((done) => {
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) {
return done(err)
}
key = _key
done()
})
})
it('marshalPublicKey and unmarshalPublicKey', () => {
const key2 = crypto.unmarshalPublicKey(crypto.marshalPublicKey(key.public))
expect(key2.equals(key.public)).to.be.eql(true)
})
it('marshalPrivateKey and unmarshalPrivateKey', (done) => {
crypto.unmarshalPrivateKey(crypto.marshalPrivateKey(key), (err, key2) => {
if (err) {
return done(err)
}
expect(key2.equals(key)).to.be.eql(true)
expect(key2.public.equals(key.public)).to.be.eql(true)
done()
})
})
// marshalled keys seem to be slightly different
// unsure as to if this is just a difference in encoding
// or a bug
describe('go interop', () => {
it('unmarshals private key', (done) => {
crypto.unmarshalPrivateKey(fixtures.private.key, (err, key) => {
if (err) {
return done(err)
}
const hash = fixtures.private.hash
expect(fixtures.private.key).to.be.eql(key.bytes)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.be.eql(hash)
done()
})
})
})
it('unmarshals public key', (done) => {
const key = crypto.unmarshalPublicKey(fixtures.public.key)
const hash = fixtures.public.hash
expect(crypto.marshalPublicKey(key)).to.be.eql(fixtures.public.key)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.be.eql(hash)
done()
})
})
it('unmarshal -> marshal, private key', (done) => {
crypto.unmarshalPrivateKey(fixtures.private.key, (err, key) => {
if (err) {
return done(err)
}
const marshalled = crypto.marshalPrivateKey(key)
expect(marshalled).to.be.eql(fixtures.private.key)
done()
})
})
it('unmarshal -> marshal, public key', () => {
const key = crypto.unmarshalPublicKey(fixtures.public.key)
const marshalled = crypto.marshalPublicKey(key)
expect(
fixtures.public.key.equals(marshalled)
).to.be.eql(
true
)
})
})
})

217
test/keys/ed25519.spec.js Normal file
View File

@@ -0,0 +1,217 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const crypto = require('../../src')
const ed25519 = crypto.keys.supportedKeys.ed25519
const fixtures = require('../fixtures/go-key-ed25519')
const testGarbage = require('../helpers/test-garbage-error-handling')
describe('ed25519', function () {
this.timeout(20 * 1000)
let key
before((done) => {
crypto.keys.generateKeyPair('Ed25519', 512, (err, _key) => {
if (err) return done(err)
key = _key
done()
})
})
it('generates a valid key', (done) => {
expect(key).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.have.length(34)
done()
})
})
it('generates a valid key from seed', (done) => {
var seed = crypto.randomBytes(32)
crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512, (err, seededkey) => {
if (err) return done(err)
expect(seededkey).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
seededkey.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.have.length(34)
done()
})
})
})
it('generates the same key from the same seed', (done) => {
var seed = crypto.randomBytes(32)
crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512, (err, seededkey1) => {
if (err) return done(err)
crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512, (err, seededkey2) => {
if (err) return done(err)
expect(seededkey1.equals(seededkey2)).to.eql(true)
expect(seededkey1.public.equals(seededkey2.public)).to.eql(true)
done()
})
})
})
it('generates different keys for different seeds', (done) => {
const seed1 = crypto.randomBytes(32)
crypto.keys.generateKeyPairFromSeed('Ed25519', seed1, 512, (err, seededkey1) => {
expect(err).to.not.exist()
const seed2 = crypto.randomBytes(32)
crypto.keys.generateKeyPairFromSeed('Ed25519', seed2, 512, (err, seededkey2) => {
expect(err).to.not.exist()
expect(seededkey1.equals(seededkey2)).to.eql(false)
expect(seededkey1.public.equals(seededkey2.public))
.to.eql(false)
done()
})
})
})
it('signs', (done) => {
const text = crypto.randomBytes(512)
key.sign(text, (err, sig) => {
expect(err).to.not.exist()
key.public.verify(text, sig, (err, res) => {
expect(err).to.not.exist()
expect(res).to.be.eql(true)
done()
})
})
})
it('encoding', (done) => {
const keyMarshal = key.marshal()
ed25519.unmarshalEd25519PrivateKey(keyMarshal, (err, key2) => {
if (err) {
return done(err)
}
const keyMarshal2 = key2.marshal()
expect(keyMarshal).to.eql(keyMarshal2)
const pk = key.public
const pkMarshal = pk.marshal()
const pk2 = ed25519.unmarshalEd25519PublicKey(pkMarshal)
const pkMarshal2 = pk2.marshal()
expect(pkMarshal).to.eql(pkMarshal2)
done()
})
})
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', (done) => {
crypto.keys.generateKeyPair('Ed25519', 512, (err, key2) => {
if (err) return done(err)
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)
done()
})
})
})
it('sign and verify', (done) => {
const data = Buffer.from('hello world')
key.sign(data, (err, sig) => {
if (err) {
return done(err)
}
key.public.verify(data, sig, (err, valid) => {
if (err) {
return done(err)
}
expect(valid).to.eql(true)
done()
})
})
})
it('fails to verify for different data', (done) => {
const data = Buffer.from('hello world')
key.sign(data, (err, sig) => {
if (err) {
return done(err)
}
key.public.verify(Buffer.from('hello'), sig, (err, valid) => {
if (err) {
return done(err)
}
expect(valid).to.be.eql(false)
done()
})
})
})
describe('returns error via cb instead of crashing', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
testGarbage.doTests('key.verify', key.verify.bind(key), 2)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
})
describe('go interop', () => {
let privateKey
before((done) => {
crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey, (err, key) => {
expect(err).to.not.exist()
privateKey = key
done()
})
})
it('verifies with data from go', (done) => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
key.verify(fixtures.verify.data, fixtures.verify.signature, (err, ok) => {
expect(err).to.not.exist()
expect(ok).to.eql(true)
done()
})
})
it('generates the same signature as go', (done) => {
privateKey.sign(fixtures.verify.data, (err, sig) => {
expect(err).to.not.exist()
expect(sig).to.eql(fixtures.verify.signature)
done()
})
})
})
})

View File

@@ -2,11 +2,14 @@
/* eslint-env mocha */ /* eslint-env mocha */
'use strict' 'use strict'
const expect = require('chai').expect const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const parallel = require('async/parallel') const parallel = require('async/parallel')
const fixtures = require('./fixtures/go-elliptic-key') const fixtures = require('../fixtures/go-elliptic-key')
const crypto = require('../src') const crypto = require('../../src')
const curves = ['P-256', 'P-384'] // 'P-521' fails in tests :( no clue why const curves = ['P-256', 'P-384'] // 'P-521' fails in tests :( no clue why
const lengths = { const lengths = {
@@ -24,15 +27,15 @@ describe('generateEphemeralKeyPair', () => {
curves.forEach((curve) => { curves.forEach((curve) => {
it(`generate and shared key ${curve}`, (done) => { it(`generate and shared key ${curve}`, (done) => {
parallel([ parallel([
(cb) => crypto.generateEphemeralKeyPair(curve, cb), (cb) => crypto.keys.generateEphemeralKeyPair(curve, cb),
(cb) => crypto.generateEphemeralKeyPair(curve, cb) (cb) => crypto.keys.generateEphemeralKeyPair(curve, cb)
], (err, keys) => { ], (err, keys) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(keys[0].key).to.have.length(lengths[curve]) expect(keys[0].key).to.have.length(lengths[curve])
expect(keys[1].key).to.have.length(lengths[curve]) expect(keys[1].key).to.have.length(lengths[curve])
keys[0].genSharedKey(keys[1].key, (err, shared) => { keys[0].genSharedKey(keys[1].key, (err, shared) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(shared).to.have.length(secretLengths[curve]) expect(shared).to.have.length(secretLengths[curve])
done() done()
}) })
@@ -45,10 +48,10 @@ describe('generateEphemeralKeyPair', () => {
const curve = fixtures.curve const curve = fixtures.curve
parallel([ parallel([
(cb) => crypto.generateEphemeralKeyPair(curve, cb), (cb) => crypto.keys.generateEphemeralKeyPair(curve, cb),
(cb) => crypto.generateEphemeralKeyPair(curve, cb) (cb) => crypto.keys.generateEphemeralKeyPair(curve, cb)
], (err, res) => { ], (err, res) => {
expect(err).to.not.exist expect(err).to.not.exist()
const alice = res[0] const alice = res[0]
const bob = res[1] const bob = res[1]
bob.key = fixtures.bob.public bob.key = fixtures.bob.public
@@ -57,14 +60,9 @@ describe('generateEphemeralKeyPair', () => {
(cb) => alice.genSharedKey(bob.key, cb), (cb) => alice.genSharedKey(bob.key, cb),
(cb) => bob.genSharedKey(alice.key, fixtures.bob, cb) (cb) => bob.genSharedKey(alice.key, fixtures.bob, cb)
], (err, secrets) => { ], (err, secrets) => {
expect(err).to.not.exist expect(err).to.not.exist()
expect(
secrets[0]
).to.be.eql(
secrets[1]
)
expect(secrets[0]).to.eql(secrets[1])
expect(secrets[0]).to.have.length(32) expect(secrets[0]).to.have.length(32)
done() done()

View File

@@ -2,10 +2,12 @@
/* eslint-env mocha */ /* eslint-env mocha */
'use strict' 'use strict'
const expect = require('chai').expect const chai = require('chai')
const dirtyChai = require('dirty-chai')
const crypto = require('../src') const expect = chai.expect
const fixtures = require('./fixtures/go-stretch-key') chai.use(dirtyChai)
const crypto = require('../../src')
const fixtures = require('../fixtures/go-stretch-key')
describe('keyStretcher', () => { describe('keyStretcher', () => {
describe('generate', () => { describe('generate', () => {
@@ -15,7 +17,7 @@ describe('keyStretcher', () => {
let secret let secret
before((done) => { before((done) => {
crypto.generateEphemeralKeyPair('P-256', (err, _res) => { crypto.keys.generateEphemeralKeyPair('P-256', (err, _res) => {
if (err) { if (err) {
return done(err) return done(err)
} }
@@ -34,13 +36,13 @@ describe('keyStretcher', () => {
ciphers.forEach((cipher) => { ciphers.forEach((cipher) => {
hashes.forEach((hash) => { hashes.forEach((hash) => {
it(`${cipher} - ${hash}`, (done) => { it(`${cipher} - ${hash}`, (done) => {
crypto.keyStretcher(cipher, hash, secret, (err, keys) => { crypto.keys.keyStretcher(cipher, hash, secret, (err, keys) => {
if (err) { if (err) {
return done(err) return done(err)
} }
expect(keys.k1).to.exist expect(keys.k1).to.exist()
expect(keys.k2).to.exist expect(keys.k2).to.exist()
done() done()
}) })
}) })
@@ -54,7 +56,7 @@ describe('keyStretcher', () => {
const cipher = test.cipher const cipher = test.cipher
const hash = test.hash const hash = test.hash
const secret = test.secret const secret = test.secret
crypto.keyStretcher(cipher, hash, secret, (err, keys) => { crypto.keys.keyStretcher(cipher, hash, secret, (err, keys) => {
if (err) { if (err) {
return done(err) return done(err)
} }

View File

@@ -1,28 +1,33 @@
/* eslint-env mocha */ /* eslint-env mocha */
'use strict' 'use strict'
const expect = require('chai').expect const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const crypto = require('../src') const crypto = require('../../src')
const rsa = crypto.keys.rsa const rsa = crypto.keys.supportedKeys.rsa
const fixtures = require('./fixtures/go-key-rsa') const fixtures = require('../fixtures/go-key-rsa')
describe('RSA', () => { const testGarbage = require('../helpers/test-garbage-error-handling')
describe('RSA', function () {
this.timeout(20 * 1000)
let key let key
before((done) => { before((done) => {
crypto.generateKeyPair('RSA', 2048, (err, _key) => { crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) return done(err) if (err) {
return done(err)
}
key = _key key = _key
done() done()
}) })
}) })
it('generates a valid key', (done) => { it('generates a valid key', (done) => {
expect( expect(key).to.be.an.instanceof(rsa.RsaPrivateKey)
key
).to.be.an.instanceof(
rsa.RsaPrivateKey
)
key.hash((err, digest) => { key.hash((err, digest) => {
if (err) { if (err) {
@@ -61,75 +66,42 @@ describe('RSA', () => {
} }
const keyMarshal2 = key2.marshal() const keyMarshal2 = key2.marshal()
expect( expect(keyMarshal).to.eql(keyMarshal2)
keyMarshal
).to.be.eql(
keyMarshal2
)
const pk = key.public const pk = key.public
const pkMarshal = pk.marshal() const pkMarshal = pk.marshal()
const pk2 = rsa.unmarshalRsaPublicKey(pkMarshal) const pk2 = rsa.unmarshalRsaPublicKey(pkMarshal)
const pkMarshal2 = pk2.marshal() const pkMarshal2 = pk2.marshal()
expect( expect(pkMarshal).to.eql(pkMarshal2)
pkMarshal
).to.be.eql(
pkMarshal2
)
done() done()
}) })
}) })
describe('key equals', () => { describe('key equals', () => {
it('equals itself', () => { it('equals itself', () => {
expect( expect(key.equals(key)).to.eql(true)
key.equals(key)
).to.be.eql(
true
)
expect( expect(key.public.equals(key.public)).to.eql(true)
key.public.equals(key.public)
).to.be.eql(
true
)
}) })
it('not equals other key', (done) => { it('not equals other key', (done) => {
crypto.generateKeyPair('RSA', 2048, (err, key2) => { crypto.keys.generateKeyPair('RSA', 2048, (err, key2) => {
if (err) return done(err) if (err) {
return done(err)
}
expect( expect(key.equals(key2)).to.eql(false)
key.equals(key2) expect(key2.equals(key)).to.eql(false)
).to.be.eql( expect(key.public.equals(key2.public)).to.eql(false)
false expect(key2.public.equals(key.public)).to.eql(false)
)
expect(
key2.equals(key)
).to.be.eql(
false
)
expect(
key.public.equals(key2.public)
).to.be.eql(
false
)
expect(
key2.public.equals(key.public)
).to.be.eql(
false
)
done() done()
}) })
}) })
}) })
it('sign and verify', (done) => { it('sign and verify', (done) => {
const data = new Buffer('hello world') const data = Buffer.from('hello world')
key.sign(data, (err, sig) => { key.sign(data, (err, sig) => {
if (err) { if (err) {
return done(err) return done(err)
@@ -146,13 +118,13 @@ describe('RSA', () => {
}) })
it('fails to verify for different data', (done) => { it('fails to verify for different data', (done) => {
const data = new Buffer('hello world') const data = Buffer.from('hello world')
key.sign(data, (err, sig) => { key.sign(data, (err, sig) => {
if (err) { if (err) {
return done(err) return done(err)
} }
key.public.verify(new Buffer('hello'), sig, (err, valid) => { key.public.verify(Buffer.from('hello'), sig, (err, valid) => {
if (err) { if (err) {
return done(err) return done(err)
} }
@@ -162,14 +134,20 @@ describe('RSA', () => {
}) })
}) })
describe('returns error via cb instead of crashing', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
testGarbage.doTests('key.verify', key.verify.bind(key), 2, true)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
})
describe('go interop', () => { describe('go interop', () => {
it('verifies with data from go', (done) => { it('verifies with data from go', (done) => {
const key = crypto.unmarshalPublicKey(fixtures.verify.publicKey) const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
key.verify(fixtures.verify.data, fixtures.verify.signature, (err, ok) => { key.verify(fixtures.verify.data, fixtures.verify.signature, (err, ok) => {
if (err) throw err if (err) throw err
expect(err).to.not.exist expect(err).to.not.exist()
expect(ok).to.be.eql(true) expect(ok).to.equal(true)
done() done()
}) })
}) })

View File

@@ -0,0 +1,99 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const fixtures = require('../fixtures/secp256k1')
const crypto = require('../../src')
const mockPublicKey = {
bytes: fixtures.pbmPublicKey
}
const mockPrivateKey = {
bytes: fixtures.pbmPrivateKey,
public: mockPublicKey
}
const mockSecp256k1Module = {
generateKeyPair (bits, callback) {
callback(null, mockPrivateKey)
},
unmarshalSecp256k1PrivateKey (buf, callback) {
callback(null, mockPrivateKey)
},
unmarshalSecp256k1PublicKey (buf) {
return mockPublicKey
}
}
describe('without libp2p-crypto-secp256k1 module present', () => {
crypto.keys.supportedKeys.secp256k1 = undefined
it('fails to generate a secp256k1 key', (done) => {
crypto.keys.generateKeyPair('secp256k1', 256, (err, key) => {
expect(err).to.exist()
expect(key).to.not.exist()
done()
})
})
it('fails to unmarshal a secp256k1 private key', (done) => {
crypto.keys.unmarshalPrivateKey(fixtures.pbmPrivateKey, (err, key) => {
expect(err).to.exist()
expect(key).to.not.exist()
done()
})
})
it('fails to unmarshal a secp256k1 public key', () => {
expect(() => {
crypto.keys.unmarshalPublicKey(fixtures.pbmPublicKey)
}).to.throw(Error)
})
})
describe('with libp2p-crypto-secp256k1 module present', () => {
let key
before((done) => {
crypto.keys.supportedKeys.secp256k1 = mockSecp256k1Module
crypto.keys.generateKeyPair('secp256k1', 256, (err, _key) => {
if (err) return done(err)
key = _key
done()
})
})
after((done) => {
delete crypto.keys.secp256k1
done()
})
it('generates a valid key', (done) => {
expect(key).to.exist()
done()
})
it('protobuf encoding', (done) => {
const keyMarshal = crypto.keys.marshalPrivateKey(key)
crypto.keys.unmarshalPrivateKey(keyMarshal, (err, key2) => {
if (err) return done(err)
const keyMarshal2 = crypto.keys.marshalPrivateKey(key2)
expect(keyMarshal).to.eql(keyMarshal2)
const pk = key.public
const pkMarshal = crypto.keys.marshalPublicKey(pk)
const pk2 = crypto.keys.unmarshalPublicKey(pkMarshal)
const pkMarshal2 = crypto.keys.marshalPublicKey(pk2)
expect(pkMarshal).to.eql(pkMarshal2)
done()
})
})
})

31
test/util.spec.js Normal file
View File

@@ -0,0 +1,31 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const util = require('../src/util')
const BN = require('bn.js')
describe('Util', () => {
let bn
before((done) => {
bn = new BN('dead', 16)
done()
})
it('toBase64', (done) => {
expect(util.toBase64(bn)).to.eql('3q0')
done()
})
it('toBase64 zero padding', (done) => {
let bnpad = new BN('ff', 16)
expect(util.toBase64(bnpad, 2)).to.eql('AP8')
done()
})
})