Compare commits

...

121 Commits

Author SHA1 Message Date
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
David Dias
f979fcd3c2 chore: release version v0.7.2 2016-11-30 11:27:17 +00:00
David Dias
0af48bbebc chore: update contributors 2016-11-30 11:27:16 +00:00
David Dias
3f9d8d557c Merge pull request #42 from libp2p/feat/better-compat
Better compatability
2016-11-30 11:23:14 +00:00
Friedel Ziegelmayer
91a3b50ac9 feat(deps): update to multihashing-async@0.3.0 2016-11-29 18:11:58 +01:00
Friedel Ziegelmayer
148d16ab25 feat(rsa): add fallback pure js fallback for webcrypto-ossl 2016-11-29 17:54:41 +01:00
Friedel Ziegelmayer
6d15450438 feat(ecdh): use node core instead of webcrypto-ossl 2016-11-29 16:36:56 +01:00
David Dias
ebe1cecdeb Merge pull request #39 from libp2p/greenkeeper-protocol-buffers-3.2.1
protocol-buffers@3.2.1
2016-11-26 13:21:08 +01:00
greenkeeperio-bot
904cfb27bd chore(package): update protocol-buffers to version 3.2.1
https://greenkeeper.io/
2016-11-26 06:11:28 +01:00
Friedel Ziegelmayer
7790beb207 Merge pull request #37 from libp2p/greenkeeper-node-webcrypto-ossl-1.0.13
node-webcrypto-ossl@1.0.13 breaks build 🚨
2016-11-23 23:26:31 +01:00
greenkeeperio-bot
6308461f0f chore(package): update node-webcrypto-ossl to version 1.0.13
https://greenkeeper.io/
2016-11-23 22:20:49 +01:00
Friedel Ziegelmayer
95a0f1f0c2 Merge pull request #34 from libp2p/greenkeeper-node-webcrypto-ossl-1.0.10
node-webcrypto-ossl@1.0.10 breaks build 🚨
2016-11-16 10:53:36 +01:00
greenkeeperio-bot
0c64122342 chore(package): update node-webcrypto-ossl to version 1.0.10
https://greenkeeper.io/
2016-11-15 07:46:24 +01:00
David Dias
ce5044b4d7 chore: release version v0.7.1 2016-11-11 08:38:28 +00:00
David Dias
1daf429a74 chore: update contributors 2016-11-11 08:38:27 +00:00
David Dias
22e95bc8a4 Merge pull request #29 from libp2p/aes-interop
AES Interop
2016-11-11 08:30:18 +00:00
Friedel Ziegelmayer
9994023490 fix(aes): replace subtle.crypto with browserify-aes
Due to the design of `AES-CTR` in the webcrypto spec, there
is no streaming mode provided. This results in the counter
not being reused between subsequent calls to `encrypt` or
`decrypt`. As both the node.js and the go implementation rely
on this webcrypto had to be replaced.
2016-11-10 17:19:45 +01:00
Friedel Ziegelmayer
393fa17512 test(aes): add failing interop tests 2016-11-10 12:55:49 +01:00
Friedel Ziegelmayer
3cc26d167f chore(benchmarks): lint happy 2016-11-07 11:37:32 +01:00
David Dias
a7c2567ba2 chore: release version v0.7.0 2016-11-03 07:46:51 +00:00
David Dias
69edfff49b chore: update contributors 2016-11-03 07:46:51 +00:00
David Dias
9a0e2585d8 chore: update deps 2016-11-03 07:46:34 +00:00
David Dias
12630dc514 Merge pull request #12 from libp2p/webcrypto
Async Crypto Endeavour
2016-11-03 07:42:05 +00:00
nikuda
b088bab80f feat: replace lib multihashing with multihashing-async 2016-11-01 12:48:36 +01:00
Friedel Ziegelmayer
cecadba14d chore: remove unused .aegir config 2016-11-01 12:47:59 +01:00
Friedel Ziegelmayer
6ebc408f73 docs: update the docs 2016-11-01 12:47:58 +01:00
Friedel Ziegelmayer
08c5df5e79 feat: use webcrypto in favor of node-forge
BREAKING CHANGE: generateKeyPair is now async
2016-11-01 12:47:58 +01:00
David Dias
1cd614237a Merge pull request #13 from RichardLitt/master
Update README URLs based on HTTP redirects
2016-10-17 20:54:27 +01:00
Richard Littauer
9795ac0722 Update README URLs based on HTTP redirects 2016-09-30 14:43:40 -04:00
David Dias
73a5258876 Merge pull request #11 from libp2p/greenkeeper-elliptic-6.3.2
elliptic@6.3.2
2016-09-26 18:59:05 +08:00
greenkeeperio-bot
c35a988331 chore(package): update elliptic to version 6.3.2
https://greenkeeper.io/
2016-09-15 13:31:22 +02:00
72 changed files with 5415 additions and 30291 deletions

View File

@@ -1,13 +0,0 @@
'use strict'
const path = require('path')
module.exports = {
webpack: {
resolve: {
alias: {
'node-forge': path.resolve(__dirname, 'vendor/forge.bundle.js')
}
}
}
}

1
.eslintignore Normal file
View File

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

11
.gitignore vendored
View File

@@ -1,6 +1,10 @@
package-lock.json
yarn.lock
**/node_modules/
**/*.log
test/repo-tests*
**/bundle.js
# Logs
logs
@@ -33,3 +37,10 @@ node_modules
lib
dist
test/test-data/go-ipfs-repo/LOCK
test/test-data/go-ipfs-repo/LOG
test/test-data/go-ipfs-repo/LOG.old
# while testing npm5
package-lock.json
yarn.lock

View File

@@ -1,19 +1,20 @@
sudo: false
language: node_js
node_js:
- 4
- 5
- stable
# Make sure we have new NPM.
before_install:
- npm install -g npm
matrix:
include:
- node_js: 6
env: CXX=g++-4.8
- node_js: 8
env: CXX=g++-4.8
# - node_js: stable
# env: CXX=g++-4.8
script:
- npm run lint
- npm test
- npm run test
- npm run coverage
- make test
before_script:
- export DISPLAY=:99.0
@@ -22,9 +23,6 @@ before_script:
after_success:
- npm run coverage-publish
env:
- CXX=g++-4.8
addons:
firefox: 'latest'
apt:

81
CHANGELOG.md Normal file
View File

@@ -0,0 +1,81 @@
<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))

144
README.md
View File

@@ -9,25 +9,33 @@
[![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-crypto.svg?style=svg)](https://circleci.com/gh/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)
![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square)
![](https://img.shields.io/badge/Node.js-%3E%3D6.0.0-orange.svg?style=flat-square)
> Crypto primitives for libp2p in JavaScript
This repo contains the JavaScript implementation of the crypto primitives
needed for libp2p. This is based on this [go implementation](https://github.com/ipfs/go-libp2p-crypto).
This repo contains the JavaScript implementation of the crypto primitives needed for libp2p. This is based on this [go implementation](https://github.com/libp2p/go-libp2p-crypto).
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [Example](#example)
- [API](#api)
- [`generateKeyPair(type, bits)`](#generatekeypairtype-bits)
- [`generateEphemeralKeyPair(curve)`](#generateephemeralkeypaircurve)
- [`keyStretcher(cipherType, hashType, secret)`](#keystretcherciphertype-hashtype-secret)
- [`marshalPublicKey(key[, type])`](#marshalpublickeykey-type)
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
- [`unmarshalPrivateKey(buf)`](#unmarshalprivatekeybuf)
- [`crypto.hmac`](#hmac)
- [`create(hash, secret, callback)`](#createhash-secret-callback)
- [`digest(data, callback)`](#digestdata-callback)
- [`crypto.aes`](#aes)
- [`create(key, iv, callback)`](#createkey-iv-callback)
- [`encrypt(data, callback)`](#encryptdata-callback)
- [`decrypt(data, callback)`](#decryptdata-callback)
- [`keys`](#keys)
- [`generateKeyPair(type, bits, callback)`](#generatekeypairtype-bits-callback)
- [`generateEphemeralKeyPair(curve, callback)`](#generateephemeralkeypaircurve-callback)
- [`keyStretcher(cipherType, hashType, secret, callback)`](#keystretcherciphertype-hashtype-secret-callback)
- [`marshalPublicKey(key[, type], callback)`](#marshalpublickeykey-type-callback)
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
- [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback)
- [`webcrypto`](#webcrypto)
- [Contribute](#contribute)
- [License](#license)
@@ -37,34 +45,84 @@ needed for libp2p. This is based on this [go implementation](https://github.com/
npm install --save libp2p-crypto
```
## Usage
### Example
```js
const crypto = require('libp2p-crypto')
var keyPair = crypto.generateKeyPair('RSA', 2048)
```
## API
### `generateKeyPair(type, bits)`
### `crypto.aes`
- `type: String`, only `'RSA'` is currently supported
- `bits: Number`
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.
#### `crypto.hmac.create(hash, secret, callback)`
- `hash: String`
- `secret: Buffer`
- `callback: Function`
##### `digest(data, callback)`
- `data: Buffer`
- `callback: Function`
Example:
```
TODO: Example of using hmac
```
### `crypto.keys`
**Supported Key Types**
The [`generateKeyPair`](#generatekeypairtype-bits-callback), [`marshalPublicKey`](#marshalpublickeykey-type-callback), and [`marshalPrivateKey`](#marshalprivatekeykey-type) functions accept a string `type` argument.
Currently the `'RSA'` and `'ed25519'` types are supported, although ed25519 keys support only signing and verification of messages. For encryption / decryption support, RSA keys should be used.
Installing the [libp2p-crypto-secp256k1](https://github.com/libp2p/js-libp2p-crypto-secp256k1) module adds support for the `'secp256k1'` type, which supports ECDSA signatures using the secp256k1 elliptic curve popularized by Bitcoin. This module is not installed by default, and should be explicitly depended on if your project requires secp256k1 support.
### `crypto.keys.generateKeyPair(type, bits, callback)`
- `type: String`, see [Supported Key Types](#supported-key-types) above.
- `bits: Number` Minimum of 1024
- `callback: Function`
Generates a keypair of the given type and bitsize.
### `generateEphemeralKeyPair(curve)`
### `crypto.keys.generateEphemeralKeyPair(curve, callback)`
- `curve: String`, one of `'P-256'`, `'P-384'`, `'P-521'` is currently supported
- `callback: Function`
Generates an ephemeral public key and returns a function that will compute the shared secret key.
Focuses only on ECDH now, but can be made more general in the future.
Returns an object of the form
Calls back with an object of the form
```js
{
key: Buffer,
@@ -72,15 +130,17 @@ Returns an object of the form
}
```
### `keyStretcher(cipherType, hashType, secret)`
### `crypto.keys.keyStretcher(cipherType, hashType, secret, callback)`
- `cipherType: String`, one of `'AES-128'`, `'AES-256'`, `'Blowfish'`
- `hashType: String`, one of `'SHA1'`, `SHA256`, `SHA512`
- `secret: Buffer`
- `callback: Function`
Generates a set of keys for each party by stretching the shared key.
Returns an object of the form
Calls back with an object of the form:
```js
{
k1: {
@@ -95,35 +155,43 @@ Returns an object of the form
}
}
```
### `marshalPublicKey(key[, type])`
- `key: crypto.rsa.RsaPublicKey`
- `type: String`, only `'RSA'` is currently supported
### `crypto.keys.marshalPublicKey(key[, type], callback)`
- `key: keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | require('libp2p-crypto-secp256k1').Secp256k1PublicKey`
- `type: String`, see [Supported Key Types](#supported-key-types) above.
Converts a public key object into a protobuf serialized public key.
### `unmarshalPublicKey(buf)`
### `crypto.keys.unmarshalPublicKey(buf)`
- `buf: Buffer`
Converts a protobuf serialized public key into its representative object.
### `marshalPrivateKey(key[, type])`
### `crypto.keys.marshalPrivateKey(key[, type])`
- `key: crypto.rsa.RsaPrivateKey`
- `type: String`, only `'RSA'` is currently supported
- `key: keys.rsa.RsaPrivateKey | keys.ed25519.Ed25519PrivateKey | require('libp2p-crypto-secp256k1').Secp256k1PrivateKey`
- `type: String`, see [Supported Key Types](#supported-key-types) above.
Converts a private key object into a protobuf serialized private key.
### `unmarshalPrivateKey(buf)`
### `crypto.keys.unmarshalPrivateKey(buf, callback)`
- `buf: Buffer`
- `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
Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/js-libp2p-crypto/issues)!
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)!
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).

View File

@@ -0,0 +1,26 @@
'use strict'
const Benchmark = require('benchmark')
const crypto = require('../src')
const suite = new Benchmark.Suite('ephemeral-keys')
const secrets = []
const curves = ['P-256', 'P-384', 'P-521']
curves.forEach((curve) => {
suite.add(`ephemeral key with secrect ${curve}`, (d) => {
crypto.keys.generateEphemeralKeyPair('P-256', (err, res) => {
if (err) { throw err }
res.genSharedKey(res.key, (err, secret) => {
if (err) { throw err }
secrets.push(secret)
d.resolve()
})
})
}, { defer: true })
})
suite.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})

View File

@@ -0,0 +1,38 @@
'use strict'
const Benchmark = require('benchmark')
const async = require('async')
const crypto = require('../src')
const suite = new Benchmark.Suite('key-stretcher')
const keys = []
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
const hashes = ['SHA1', 'SHA256', 'SHA512']
async.waterfall([
(cb) => crypto.keys.generateEphemeralKeyPair('P-256', cb),
(res, cb) => res.genSharedKey(res.key, cb)
], (err, secret) => {
if (err) { throw err }
ciphers.forEach((cipher) => hashes.forEach((hash) => {
setup(cipher, hash, secret)
}))
suite.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
})
function setup (cipher, hash, secret) {
suite.add(`keyStretcher ${cipher} ${hash}`, (d) => {
crypto.keys.keyStretcher(cipher, hash, secret, (err, k) => {
if (err) { throw err }
keys.push(k)
d.resolve()
})
}, { defer: true })
}

41
benchmarks/rsa.js Normal file
View File

@@ -0,0 +1,41 @@
'use strict'
const Benchmark = require('benchmark')
const crypto = require('../src')
const suite = new Benchmark.Suite('rsa')
const keys = []
const bits = [1024, 2048, 4096]
bits.forEach((bit) => {
suite.add(`generateKeyPair ${bit}bits`, (d) => {
crypto.keys.generateKeyPair('RSA', bit, (err, key) => {
if (err) { throw err }
keys.push(key)
d.resolve()
})
}, {
defer: true
})
})
suite.add('sign and verify', (d) => {
const key = keys[0]
const text = key.genSecret()
key.sign(text, (err, sig) => {
if (err) { throw err }
key.public.verify(text, sig, (err, res) => {
if (err) { throw err }
if (res !== true) { throw new Error('failed to verify') }
d.resolve()
})
})
}, {
defer: true
})
suite.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})

View File

@@ -5,8 +5,10 @@ machine:
dependencies:
pre:
- google-chrome --version
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
- curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo dpkg -i google-chrome.deb || true
- 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

View File

@@ -1,12 +1,18 @@
{
"name": "libp2p-crypto",
"version": "0.6.1",
"version": "0.10.1",
"description": "Crypto primitives for libp2p",
"main": "lib/index.js",
"jsnext:main": "src/index.js",
"main": "src/index.js",
"browser": {
"./src/hmac/index.js": "./src/hmac/index-browser.js",
"./src/keys/ecdh.js": "./src/keys/ecdh-browser.js",
"./src/aes/ciphers.js": "./src/aes/ciphers-browser.js",
"./src/keys/rsa.js": "./src/keys/rsa-browser.js"
},
"scripts": {
"lint": "aegir-lint",
"build": "aegir-build",
"build-proto": "pbjs --wrap commonjs --target static-module src/keys/keys.proto > src/keys/keys.proto.js",
"test": "aegir-test",
"test:node": "aegir-test --env node",
"test:browser": "aegir-test --env browser",
@@ -22,38 +28,55 @@
"crypto",
"rsa"
],
"author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>",
"author": "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"license": "MIT",
"dependencies": {
"elliptic": "^6.2.3",
"multihashing": "^0.2.1",
"node-forge": "^0.6.39",
"protocol-buffers": "^3.1.6"
"asn1.js": "^4.9.1",
"async": "^2.5.0",
"browserify-aes": "^1.0.6",
"keypair": "^1.0.1",
"libp2p-crypto-secp256k1": "~0.2.2",
"multihashing-async": "~0.4.6",
"pem-jwk": "^1.5.1",
"protobufjs": "^6.8.0",
"rsa-pem-to-jwk": "^1.1.3",
"safe-buffer": "^5.1.1",
"tweetnacl": "^1.0.0",
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
},
"devDependencies": {
"aegir": "^8.0.0",
"chai": "^3.5.0",
"pre-commit": "^1.1.3"
"aegir": "^11.0.2",
"benchmark": "^2.1.4",
"chai": "^4.1.2",
"dirty-chai": "^2.0.1",
"pre-commit": "^1.2.2"
},
"pre-commit": [
"lint",
"test"
],
"engines": {
"node": "^4.0.0"
"node": ">=6.0.0",
"npm": ">=3.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/ipfs/js-libp2p-crypto.git"
"url": "https://github.com/libp2p/js-libp2p-crypto.git"
},
"bugs": {
"url": "https://github.com/ipfs/js-libp2p-crypto/issues"
"url": "https://github.com/libp2p/js-libp2p-crypto/issues"
},
"homepage": "https://github.com/ipfs/js-libp2p-crypto",
"homepage": "https://github.com/libp2p/js-libp2p-crypto",
"contributors": [
"David Dias <daviddias.p@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Greenkeeper <support@greenkeeper.io>",
"Jack Kleeman <jackkleeman@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>"
]
}

View File

@@ -0,0 +1,8 @@
'use strict'
const crypto = require('browserify-aes')
module.exports = {
createCipheriv: crypto.createCipheriv,
createDecipheriv: crypto.createDecipheriv
}

8
src/aes/ciphers.js Normal file
View File

@@ -0,0 +1,8 @@
'use strict'
const crypto = require('crypto')
module.exports = {
createCipheriv: crypto.createCipheriv,
createDecipheriv: crypto.createDecipheriv
}

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)
}

30
src/aes/index.js Normal file
View File

@@ -0,0 +1,30 @@
'use strict'
const ciphers = require('./ciphers')
const CIPHER_MODES = {
16: 'aes-128-ctr',
32: 'aes-256-ctr'
}
exports.create = function (key, iv, callback) {
const mode = CIPHER_MODES[key.length]
if (!mode) {
return callback(new Error('Invalid key length'))
}
const cipher = ciphers.createCipheriv(mode, key, iv)
const decipher = ciphers.createDecipheriv(mode, key, iv)
const res = {
encrypt (data, cb) {
cb(null, cipher.update(data))
},
decrypt (data, cb) {
cb(null, decipher.update(data))
}
}
callback(null, res)
}

View File

@@ -1,13 +0,0 @@
enum KeyType {
RSA = 0;
}
message PublicKey {
required KeyType Type = 1;
required bytes Data = 2;
}
message PrivateKey {
required KeyType Type = 1;
required bytes Data = 2;
}

View File

@@ -1,36 +0,0 @@
'use strict'
const EC = require('elliptic').ec
const curveMap = {
'P-256': 'p256',
'P-384': 'p384',
'P-521': 'p521'
}
// Generates an ephemeral public key and returns a function that will compute
// the shared secret key.
//
// Focuses only on ECDH now, but can be made more general in the future.
module.exports = (curveName) => {
const curve = curveMap[curveName]
if (!curve) {
throw new Error('unsupported curve passed')
}
const ec = new EC(curve)
const priv = ec.genKeyPair()
// forcePrivate is used for testing only
const genSharedKey = (theirPub, forcePrivate) => {
const pub = ec.keyFromPublic(theirPub, 'hex')
const p = forcePrivate || priv
return p.derive(pub.getPublic()).toBuffer('be')
}
return {
key: new Buffer(priv.getPublic('hex'), 'hex'),
genSharedKey
}
}

40
src/hmac/index-browser.js Normal file
View File

@@ -0,0 +1,40 @@
'use strict'
const nodeify = require('../nodeify')
const Buffer = require('safe-buffer').Buffer
const crypto = require('../webcrypto.js')()
const lengths = require('./lengths')
const hashTypes = {
SHA1: 'SHA-1',
SHA256: 'SHA-256',
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) {
const hash = hashTypes[hashType]
nodeify(crypto.subtle.importKey(
'raw',
secret,
{
name: 'HMAC',
hash: {name: hash}
},
false,
['sign']
).then((key) => {
return {
digest (data, cb) {
sign(key, data, cb)
},
length: lengths[hashType]
}
}), callback)
}

21
src/hmac/index.js Normal file
View File

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

7
src/hmac/lengths.js Normal file
View File

@@ -0,0 +1,7 @@
'use strict'
module.exports = {
SHA1: 20,
SHA256: 32,
SHA512: 64
}

View File

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

View File

@@ -1,95 +0,0 @@
'use strict'
const forge = require('node-forge')
const createBuffer = forge.util.createBuffer
const cipherMap = {
'AES-128': {
ivSize: 16,
keySize: 16
},
'AES-256': {
ivSize: 16,
keySize: 32
},
Blowfish: {
ivSize: 8,
cipherKeySize: 32
}
}
const hashMap = {
SHA1: 'sha1',
SHA256: 'sha256',
// workaround for https://github.com/digitalbazaar/forge/issues/401
SHA512: forge.md.sha512.create()
}
// Generates a set of keys for each party by stretching the shared key.
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
module.exports = (cipherType, hashType, secret) => {
const cipher = cipherMap[cipherType]
const hash = hashMap[hashType]
if (!cipher) {
throw new Error('unkown cipherType passed')
}
if (!hash) {
throw new Error('unkown hashType passed')
}
if (Buffer.isBuffer(secret)) {
secret = createBuffer(secret.toString('binary'))
}
const cipherKeySize = cipher.keySize
const ivSize = cipher.ivSize
const hmacKeySize = 20
const seed = 'key expansion'
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
const m = forge.hmac.create()
m.start(hash, secret)
m.update(seed)
let a = m.digest().bytes()
const result = createBuffer()
let j = 0
for (; j < resultLength;) {
m.start(hash, secret)
m.update(a)
m.update(seed)
const b = createBuffer(m.digest(), 'raw')
let todo = b.length()
if (j + todo > resultLength) {
todo = resultLength - j
}
result.putBytes(b.getBytes(todo))
j += todo
m.start(hash, secret)
m.update(a)
a = m.digest().bytes()
}
const half = resultLength / 2
const r1 = createBuffer(result.getBytes(half))
const r2 = createBuffer(result.getBytes())
const createKey = (res) => ({
iv: new Buffer(res.getBytes(ivSize), 'binary'),
cipherKey: new Buffer(res.getBytes(cipherKeySize), 'binary'),
macKey: new Buffer(res.getBytes(), 'binary')
})
return {
k1: createKey(r1),
k2: createKey(r2)
}
}

128
src/keys/ecdh-browser.js Normal file
View File

@@ -0,0 +1,128 @@
'use strict'
const webcrypto = require('../webcrypto.js')()
const nodeify = require('../nodeify')
const BN = require('asn1.js').bignum
const Buffer = require('safe-buffer').Buffer
const util = require('../util')
const toBase64 = util.toBase64
const toBn = util.toBn
const bits = {
'P-256': 256,
'P-384': 384,
'P-521': 521
}
exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(webcrypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: curve
},
true,
['deriveBits']
).then((pair) => {
// forcePrivate is used for testing only
const genSharedKey = (theirPub, forcePrivate, cb) => {
if (typeof forcePrivate === 'function') {
cb = forcePrivate
forcePrivate = undefined
}
let privateKey
if (forcePrivate) {
privateKey = webcrypto.subtle.importKey(
'jwk',
unmarshalPrivateKey(curve, forcePrivate),
{
name: 'ECDH',
namedCurve: curve
},
false,
['deriveBits']
)
} else {
privateKey = Promise.resolve(pair.privateKey)
}
const keys = Promise.all([
webcrypto.subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
name: 'ECDH',
namedCurve: curve
},
false,
[]
),
privateKey
])
nodeify(keys.then((keys) => webcrypto.subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
public: keys[0]
},
keys[1],
bits[curve]
)).then((bits) => Buffer.from(bits)), cb)
}
return webcrypto.subtle.exportKey('jwk', pair.publicKey)
.then((publicKey) => {
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
})
}), callback)
}
const curveLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
// Marshal converts a jwk encodec ECDH public key into the
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
// go-ipfs uses)
function marshalPublicKey (jwk) {
const byteLen = curveLengths[jwk.crv]
return Buffer.concat([
Buffer.from([4]), // uncompressed point
toBn(jwk.x).toArrayLike(Buffer, 'be', byteLen),
toBn(jwk.y).toArrayLike(Buffer, 'be', byteLen)
], 1 + byteLen * 2)
}
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(Buffer.from([4]))) {
throw new Error('Invalid key format')
}
const x = new BN(key.slice(1, byteLen + 1))
const y = new BN(key.slice(1 + byteLen))
return {
kty: 'EC',
crv: curve,
x: toBase64(x, byteLen),
y: toBase64(y, byteLen),
ext: true
}
}
function unmarshalPrivateKey (curve, key) {
const result = unmarshalPublicKey(curve, key.public)
result.d = toBase64(new BN(key.private))
return result
}

41
src/keys/ecdh.js Normal file
View File

@@ -0,0 +1,41 @@
'use strict'
const crypto = require('crypto')
const setImmediate = require('async/setImmediate')
const curves = {
'P-256': 'prime256v1',
'P-384': 'secp384r1',
'P-521': 'secp521r1'
}
exports.generateEphmeralKeyPair = function (curve, callback) {
if (!curves[curve]) {
return callback(new Error(`Unkown curve: ${curve}`))
}
const ecdh = crypto.createECDH(curves[curve])
ecdh.generateKeys()
setImmediate(() => callback(null, {
key: ecdh.getPublicKey(),
genSharedKey (theirPub, forcePrivate, cb) {
if (typeof forcePrivate === 'function') {
cb = forcePrivate
forcePrivate = null
}
if (forcePrivate) {
ecdh.setPrivateKey(forcePrivate.private)
}
let secret
try {
secret = ecdh.computeSecret(theirPub)
} catch (err) {
return cb(err)
}
setImmediate(() => cb(null, secret))
}
}))
}

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

@@ -0,0 +1,166 @@
'use strict'
const multihashing = require('multihashing-async')
const Buffer = require('safe-buffer').Buffer
const crypto = require('./ed25519')
const pbm = require('./keys.proto.js')
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 () {
const msg = pbm.PublicKey.create({
Type: pbm.KeyType.Ed25519,
Data: this.marshal()
})
return Buffer.from(pbm.PublicKey.encode(msg).finish())
}
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 () {
const msg = pbm.PrivateKey.create({
Type: pbm.KeyType.Ed25519,
Data: this.marshal()
})
return Buffer.from(pbm.PrivateKey.encode(msg).finish())
}
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
}

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

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

View File

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

View File

@@ -1,5 +1,110 @@
'use strict'
module.exports = {
rsa: require('./rsa')
const keysPBM = require('./keys.proto.js')
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 = Buffer.from(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) => {
const decoded = keysPBM.PrivateKey.decode(buf)
const data = Buffer.from(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
}

109
src/keys/key-stretcher.js Normal file
View File

@@ -0,0 +1,109 @@
'use strict'
const whilst = require('async/whilst')
const Buffer = require('safe-buffer').Buffer
const hmac = require('../hmac')
const cipherMap = {
'AES-128': {
ivSize: 16,
keySize: 16
},
'AES-256': {
ivSize: 16,
keySize: 32
},
Blowfish: {
ivSize: 8,
cipherKeySize: 32
}
}
// Generates a set of keys for each party by stretching the shared key.
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
module.exports = (cipherType, hash, secret, callback) => {
const cipher = cipherMap[cipherType]
if (!cipher) {
return callback(new Error('unkown cipherType passed'))
}
if (!hash) {
return callback(new Error('unkown hashType passed'))
}
const cipherKeySize = cipher.keySize
const ivSize = cipher.ivSize
const hmacKeySize = 20
const seed = Buffer.from('key expansion')
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
hmac.create(hash, secret, (err, m) => {
if (err) {
return callback(err)
}
m.digest(seed, (err, a) => {
if (err) {
return callback(err)
}
let result = []
let j = 0
whilst(
() => j < resultLength,
stretch,
finish
)
function stretch (cb) {
m.digest(Buffer.concat([a, seed]), (err, b) => {
if (err) {
return cb(err)
}
let todo = b.length
if (j + todo > resultLength) {
todo = resultLength - j
}
result.push(b)
j += todo
m.digest(a, (err, _a) => {
if (err) {
return cb(err)
}
a = _a
cb()
})
})
}
function finish (err) {
if (err) {
return callback(err)
}
const half = resultLength / 2
const resultBuffer = Buffer.concat(result)
const r1 = resultBuffer.slice(0, half)
const r2 = resultBuffer.slice(half, resultLength)
const createKey = (res) => ({
iv: res.slice(0, ivSize),
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
macKey: res.slice(ivSize + cipherKeySize)
})
callback(null, {
k1: createKey(r1),
k2: createKey(r2)
})
}
})
})
}

15
src/keys/keys.proto Normal file
View File

@@ -0,0 +1,15 @@
enum KeyType {
RSA = 0;
Ed25519 = 1;
Secp256k1 = 2;
}
message PublicKey {
required KeyType Type = 1;
required bytes Data = 2;
}
message PrivateKey {
required KeyType Type = 1;
required bytes Data = 2;
}

488
src/keys/keys.proto.js Normal file
View File

@@ -0,0 +1,488 @@
/*eslint-disable block-scoped-var, no-redeclare, no-control-regex, no-prototype-builtins*/
"use strict";
var $protobuf = require("protobufjs/minimal");
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
// Exported root namespace
var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
/**
* KeyType enum.
* @exports KeyType
* @enum {string}
* @property {number} RSA=0 RSA value
* @property {number} Ed25519=1 Ed25519 value
* @property {number} Secp256k1=2 Secp256k1 value
*/
$root.KeyType = (function() {
var valuesById = {}, values = Object.create(valuesById);
values[valuesById[0] = "RSA"] = 0;
values[valuesById[1] = "Ed25519"] = 1;
values[valuesById[2] = "Secp256k1"] = 2;
return values;
})();
$root.PublicKey = (function() {
/**
* Properties of a PublicKey.
* @exports IPublicKey
* @interface IPublicKey
* @property {KeyType} Type PublicKey Type
* @property {Uint8Array} Data PublicKey Data
*/
/**
* Constructs a new PublicKey.
* @exports PublicKey
* @classdesc Represents a PublicKey.
* @constructor
* @param {IPublicKey=} [properties] Properties to set
*/
function PublicKey(properties) {
if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* PublicKey Type.
* @member {KeyType}Type
* @memberof PublicKey
* @instance
*/
PublicKey.prototype.Type = 0;
/**
* PublicKey Data.
* @member {Uint8Array}Data
* @memberof PublicKey
* @instance
*/
PublicKey.prototype.Data = $util.newBuffer([]);
/**
* Creates a new PublicKey instance using the specified properties.
* @function create
* @memberof PublicKey
* @static
* @param {IPublicKey=} [properties] Properties to set
* @returns {PublicKey} PublicKey instance
*/
PublicKey.create = function create(properties) {
return new PublicKey(properties);
};
/**
* Encodes the specified PublicKey message. Does not implicitly {@link PublicKey.verify|verify} messages.
* @function encode
* @memberof PublicKey
* @static
* @param {IPublicKey} message PublicKey message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
PublicKey.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.Type);
writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.Data);
return writer;
};
/**
* Encodes the specified PublicKey message, length delimited. Does not implicitly {@link PublicKey.verify|verify} messages.
* @function encodeDelimited
* @memberof PublicKey
* @static
* @param {IPublicKey} message PublicKey message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
PublicKey.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a PublicKey message from the specified reader or buffer.
* @function decode
* @memberof PublicKey
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {PublicKey} PublicKey
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
PublicKey.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.PublicKey();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.Type = reader.int32();
break;
case 2:
message.Data = reader.bytes();
break;
default:
reader.skipType(tag & 7);
break;
}
}
if (!message.hasOwnProperty("Type"))
throw $util.ProtocolError("missing required 'Type'", { instance: message });
if (!message.hasOwnProperty("Data"))
throw $util.ProtocolError("missing required 'Data'", { instance: message });
return message;
};
/**
* Decodes a PublicKey message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof PublicKey
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {PublicKey} PublicKey
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
PublicKey.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a PublicKey message.
* @function verify
* @memberof PublicKey
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
PublicKey.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
switch (message.Type) {
default:
return "Type: enum value expected";
case 0:
case 1:
case 2:
break;
}
if (!(message.Data && typeof message.Data.length === "number" || $util.isString(message.Data)))
return "Data: buffer expected";
return null;
};
/**
* Creates a PublicKey message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof PublicKey
* @static
* @param {Object.<string,*>} object Plain object
* @returns {PublicKey} PublicKey
*/
PublicKey.fromObject = function fromObject(object) {
if (object instanceof $root.PublicKey)
return object;
var message = new $root.PublicKey();
switch (object.Type) {
case "RSA":
case 0:
message.Type = 0;
break;
case "Ed25519":
case 1:
message.Type = 1;
break;
case "Secp256k1":
case 2:
message.Type = 2;
break;
}
if (object.Data != null)
if (typeof object.Data === "string")
$util.base64.decode(object.Data, message.Data = $util.newBuffer($util.base64.length(object.Data)), 0);
else if (object.Data.length)
message.Data = object.Data;
return message;
};
/**
* Creates a plain object from a PublicKey message. Also converts values to other types if specified.
* @function toObject
* @memberof PublicKey
* @static
* @param {PublicKey} message PublicKey
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
PublicKey.toObject = function toObject(message, options) {
if (!options)
options = {};
var object = {};
if (options.defaults) {
object.Type = options.enums === String ? "RSA" : 0;
object.Data = options.bytes === String ? "" : [];
}
if (message.Type != null && message.hasOwnProperty("Type"))
object.Type = options.enums === String ? $root.KeyType[message.Type] : message.Type;
if (message.Data != null && message.hasOwnProperty("Data"))
object.Data = options.bytes === String ? $util.base64.encode(message.Data, 0, message.Data.length) : options.bytes === Array ? Array.prototype.slice.call(message.Data) : message.Data;
return object;
};
/**
* Converts this PublicKey to JSON.
* @function toJSON
* @memberof PublicKey
* @instance
* @returns {Object.<string,*>} JSON object
*/
PublicKey.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return PublicKey;
})();
$root.PrivateKey = (function() {
/**
* Properties of a PrivateKey.
* @exports IPrivateKey
* @interface IPrivateKey
* @property {KeyType} Type PrivateKey Type
* @property {Uint8Array} Data PrivateKey Data
*/
/**
* Constructs a new PrivateKey.
* @exports PrivateKey
* @classdesc Represents a PrivateKey.
* @constructor
* @param {IPrivateKey=} [properties] Properties to set
*/
function PrivateKey(properties) {
if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* PrivateKey Type.
* @member {KeyType}Type
* @memberof PrivateKey
* @instance
*/
PrivateKey.prototype.Type = 0;
/**
* PrivateKey Data.
* @member {Uint8Array}Data
* @memberof PrivateKey
* @instance
*/
PrivateKey.prototype.Data = $util.newBuffer([]);
/**
* Creates a new PrivateKey instance using the specified properties.
* @function create
* @memberof PrivateKey
* @static
* @param {IPrivateKey=} [properties] Properties to set
* @returns {PrivateKey} PrivateKey instance
*/
PrivateKey.create = function create(properties) {
return new PrivateKey(properties);
};
/**
* Encodes the specified PrivateKey message. Does not implicitly {@link PrivateKey.verify|verify} messages.
* @function encode
* @memberof PrivateKey
* @static
* @param {IPrivateKey} message PrivateKey message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
PrivateKey.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.Type);
writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.Data);
return writer;
};
/**
* Encodes the specified PrivateKey message, length delimited. Does not implicitly {@link PrivateKey.verify|verify} messages.
* @function encodeDelimited
* @memberof PrivateKey
* @static
* @param {IPrivateKey} message PrivateKey message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
PrivateKey.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a PrivateKey message from the specified reader or buffer.
* @function decode
* @memberof PrivateKey
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {PrivateKey} PrivateKey
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
PrivateKey.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.PrivateKey();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.Type = reader.int32();
break;
case 2:
message.Data = reader.bytes();
break;
default:
reader.skipType(tag & 7);
break;
}
}
if (!message.hasOwnProperty("Type"))
throw $util.ProtocolError("missing required 'Type'", { instance: message });
if (!message.hasOwnProperty("Data"))
throw $util.ProtocolError("missing required 'Data'", { instance: message });
return message;
};
/**
* Decodes a PrivateKey message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof PrivateKey
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {PrivateKey} PrivateKey
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
PrivateKey.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a PrivateKey message.
* @function verify
* @memberof PrivateKey
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
PrivateKey.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
switch (message.Type) {
default:
return "Type: enum value expected";
case 0:
case 1:
case 2:
break;
}
if (!(message.Data && typeof message.Data.length === "number" || $util.isString(message.Data)))
return "Data: buffer expected";
return null;
};
/**
* Creates a PrivateKey message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof PrivateKey
* @static
* @param {Object.<string,*>} object Plain object
* @returns {PrivateKey} PrivateKey
*/
PrivateKey.fromObject = function fromObject(object) {
if (object instanceof $root.PrivateKey)
return object;
var message = new $root.PrivateKey();
switch (object.Type) {
case "RSA":
case 0:
message.Type = 0;
break;
case "Ed25519":
case 1:
message.Type = 1;
break;
case "Secp256k1":
case 2:
message.Type = 2;
break;
}
if (object.Data != null)
if (typeof object.Data === "string")
$util.base64.decode(object.Data, message.Data = $util.newBuffer($util.base64.length(object.Data)), 0);
else if (object.Data.length)
message.Data = object.Data;
return message;
};
/**
* Creates a plain object from a PrivateKey message. Also converts values to other types if specified.
* @function toObject
* @memberof PrivateKey
* @static
* @param {PrivateKey} message PrivateKey
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
PrivateKey.toObject = function toObject(message, options) {
if (!options)
options = {};
var object = {};
if (options.defaults) {
object.Type = options.enums === String ? "RSA" : 0;
object.Data = options.bytes === String ? "" : [];
}
if (message.Type != null && message.hasOwnProperty("Type"))
object.Type = options.enums === String ? $root.KeyType[message.Type] : message.Type;
if (message.Data != null && message.hasOwnProperty("Data"))
object.Data = options.bytes === String ? $util.base64.encode(message.Data, 0, message.Data.length) : options.bytes === Array ? Array.prototype.slice.call(message.Data) : message.Data;
return object;
};
/**
* Converts this PrivateKey to JSON.
* @function toJSON
* @memberof PrivateKey
* @instance
* @returns {Object.<string,*>} JSON object
*/
PrivateKey.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return PrivateKey;
})();
module.exports = $root;

120
src/keys/rsa-browser.js Normal file
View File

@@ -0,0 +1,120 @@
'use strict'
const nodeify = require('../nodeify')
const Buffer = require('safe-buffer').Buffer
const webcrypto = require('../webcrypto.js')()
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
nodeify(webcrypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: 'SHA-256'}
},
true,
['sign', 'verify']
)
.then(exportKey)
.then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
const privateKey = webcrypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
true,
['sign']
)
nodeify(Promise.all([
privateKey,
derivePublicFromPrivate(key)
]).then((keys) => exportKey({
privateKey: keys[0],
publicKey: keys[1]
})).then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
exports.getRandomValues = function (arr) {
return Buffer.from(webcrypto.getRandomValues(arr))
}
exports.hashAndSign = function (key, msg, callback) {
nodeify(webcrypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
false,
['sign']
).then((privateKey) => {
return webcrypto.subtle.sign(
{name: 'RSASSA-PKCS1-v1_5'},
privateKey,
Uint8Array.from(msg)
)
}).then((sig) => Buffer.from(sig)), callback)
}
exports.hashAndVerify = function (key, sig, msg, callback) {
nodeify(webcrypto.subtle.importKey(
'jwk',
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
false,
['verify']
).then((publicKey) => {
return webcrypto.subtle.verify(
{name: 'RSASSA-PKCS1-v1_5'},
publicKey,
sig,
msg
)
}), callback)
}
function exportKey (pair) {
return Promise.all([
webcrypto.subtle.exportKey('jwk', pair.privateKey),
webcrypto.subtle.exportKey('jwk', pair.publicKey)
])
}
function derivePublicFromPrivate (jwKey) {
return webcrypto.subtle.importKey(
'jwk',
{
kty: jwKey.kty,
n: jwKey.n,
e: jwKey.e,
alg: jwKey.alg,
kid: jwKey.kid
},
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
},
true,
['verify']
)
}

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

@@ -0,0 +1,134 @@
'use strict'
const multihashing = require('multihashing-async')
const crypto = require('./rsa')
const pbm = require('./keys.proto.js')
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 () {
const msg = pbm.PublicKey.create({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
return Buffer.from(pbm.PublicKey.encode(msg).finish())
}
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 () {
const msg = pbm.PrivateKey.create({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
return Buffer.from(pbm.PrivateKey.encode(msg).finish())
}
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
}

114
src/keys/rsa-utils.js Normal file
View File

@@ -0,0 +1,114 @@
'use strict'
const asn1 = require('asn1.js')
const util = require('./../util')
const toBase64 = util.toBase64
const toBn = util.toBn
const RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
this.seq().obj(
this.key('version').int(),
this.key('modulus').int(),
this.key('publicExponent').int(),
this.key('privateExponent').int(),
this.key('prime1').int(),
this.key('prime2').int(),
this.key('exponent1').int(),
this.key('exponent2').int(),
this.key('coefficient').int()
)
})
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
this.seq().obj(
this.key('algorithm').objid({
'1.2.840.113549.1.1.1': 'rsa'
}),
this.key('none').optional().null_(),
this.key('curve').optional().objid(),
this.key('params').optional().seq().obj(
this.key('p').int(),
this.key('q').int(),
this.key('g').int()
)
)
})
const PublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('algorithm').use(AlgorithmIdentifier),
this.key('subjectPublicKey').bitstr()
)
})
const RSAPublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('modulus').int(),
this.key('publicExponent').int()
)
})
// Convert a PKCS#1 in ASN1 DER format to a JWK key
exports.pkcs1ToJwk = function (bytes) {
const asn1 = RSAPrivateKey.decode(bytes, 'der')
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
d: toBase64(asn1.privateExponent),
p: toBase64(asn1.prime1),
q: toBase64(asn1.prime2),
dp: toBase64(asn1.exponent1),
dq: toBase64(asn1.exponent2),
qi: toBase64(asn1.coefficient),
alg: 'RS256',
kid: '2011-04-29'
}
}
// Convert a JWK key into PKCS#1 in ASN1 DER format
exports.jwkToPkcs1 = function (jwk) {
return RSAPrivateKey.encode({
version: 0,
modulus: toBn(jwk.n),
publicExponent: toBn(jwk.e),
privateExponent: toBn(jwk.d),
prime1: toBn(jwk.p),
prime2: toBn(jwk.q),
exponent1: toBn(jwk.dp),
exponent2: toBn(jwk.dq),
coefficient: toBn(jwk.qi)
}, 'der')
}
// Convert a PKCIX in ASN1 DER format to a JWK key
exports.pkixToJwk = function (bytes) {
const ndata = PublicKey.decode(bytes, 'der')
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
return {
kty: 'RSA',
n: toBase64(asn1.modulus),
e: toBase64(asn1.publicExponent),
alg: 'RS256',
kid: '2011-04-29'
}
}
// Convert a JWK key to PKCIX in ASN1 DER format
exports.jwkToPkix = function (jwk) {
return PublicKey.encode({
algorithm: {
algorithm: 'rsa',
none: null
},
subjectPublicKey: {
data: RSAPublicKey.encode({
modulus: toBn(jwk.n),
publicExponent: toBn(jwk.e)
}, 'der')
}
}, 'der')
}

View File

@@ -1,141 +1,56 @@
'use strict'
const forge = require('node-forge')
const protobuf = require('protocol-buffers')
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const keypair = require('keypair')
const setImmediate = require('async/setImmediate')
const pemToJwk = require('pem-jwk').pem2jwk
const jwkToPem = require('pem-jwk').jwk2pem
const utils = require('../utils')
exports.utils = require('./rsa-utils')
const pki = forge.pki
const rsa = pki.rsa
exports.generateKey = function (bits, callback) {
const done = (err, res) => setImmediate(() => callback(err, res))
const pbm = protobuf(fs.readFileSync(path.join(__dirname, '../crypto.proto')))
class RsaPublicKey {
constructor (k) {
this._key = k
let key
try {
key = keypair({ bits: bits })
} catch (err) {
return done(err)
}
verify (data, sig) {
const md = forge.md.sha256.create()
if (Buffer.isBuffer(data)) {
md.update(data.toString('binary'), 'binary')
} else {
md.update(data)
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
}
return this._key.verify(md.digest().bytes(), sig)
}
marshal () {
return new Buffer(forge.asn1.toDer(pki.publicKeyToAsn1(this._key)).bytes(), 'binary')
}
get bytes () {
return pbm.PublicKey.encode({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
encrypt (bytes) {
return this._key.encrypt(bytes, 'RSAES-PKCS1-V1_5')
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash () {
return utils.keyHash(this.bytes)
}
})
}
class RsaPrivateKey {
constructor (privKey, pubKey) {
this._privateKey = privKey
if (pubKey) {
this._publicKey = pubKey
} else {
this._publicKey = forge.pki.setRsaPublicKey(privKey.n, privKey.e)
}
}
genSecret () {
return forge.random.getBytesSync(16)
}
sign (message) {
const md = forge.md.sha256.create()
if (Buffer.isBuffer(message)) {
md.update(message.toString('binary'), 'binary')
} else {
md.update(message)
}
const raw = this._privateKey.sign(md, 'RSASSA-PKCS1-V1_5')
return new Buffer(raw, 'binary')
}
get public () {
if (!this._publicKey) {
throw new Error('public key not provided')
}
return new RsaPublicKey(this._publicKey)
}
decrypt (bytes) {
return this._privateKey.decrypt(bytes, 'RSAES-PKCS1-V1_5')
}
marshal () {
return new Buffer(forge.asn1.toDer(pki.privateKeyToAsn1(this._privateKey)).bytes(), 'binary')
}
get bytes () {
return pbm.PrivateKey.encode({
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
equals (key) {
return this.bytes.equals(key.bytes)
}
hash () {
return utils.keyHash(this.bytes)
}
exports.getRandomValues = function (arr) {
return crypto.randomBytes(arr.length)
}
function unmarshalRsaPrivateKey (bytes) {
if (Buffer.isBuffer(bytes)) {
bytes = forge.util.createBuffer(bytes.toString('binary'))
}
const key = pki.privateKeyFromAsn1(forge.asn1.fromDer(bytes))
exports.hashAndSign = function (key, msg, callback) {
const sign = crypto.createSign('RSA-SHA256')
return new RsaPrivateKey(key)
sign.update(msg)
setImmediate(() => callback(null, sign.sign(jwkToPem(key))))
}
function unmarshalRsaPublicKey (bytes) {
if (Buffer.isBuffer(bytes)) {
bytes = forge.util.createBuffer(bytes.toString('binary'))
}
const key = pki.publicKeyFromAsn1(forge.asn1.fromDer(bytes))
exports.hashAndVerify = function (key, sig, msg, callback) {
const verify = crypto.createVerify('RSA-SHA256')
return new RsaPublicKey(key)
}
verify.update(msg)
function generateKeyPair (bits) {
const p = rsa.generateKeyPair({bits})
return new RsaPrivateKey(p.privateKey, p.publicKey)
}
module.exports = {
RsaPublicKey,
RsaPrivateKey,
unmarshalRsaPublicKey,
unmarshalRsaPrivateKey,
generateKeyPair
setImmediate(() => callback(null, verify.verify(jwkToPem(key), sig)))
}

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

21
src/util.js Normal file
View File

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

View File

@@ -1,8 +0,0 @@
'use strict'
const multihashing = require('multihashing')
// Hashes a key
exports.keyHash = (bytes) => {
return multihashing(bytes, 'sha2-256')
}

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')
}

153
stats.md Normal file
View File

@@ -0,0 +1,153 @@
# Stats
## Size
| | non-minified | minified |
|-------|--------------|----------|
|before | `1.8M` | `949K` |
|after | `606K` | `382K` |
## Performance
### RSA
#### Before
##### Node `6.6.0`
```
generateKeyPair 1024bits x 3.51 ops/sec ±29.45% (22 runs sampled)
generateKeyPair 2048bits x 0.17 ops/sec ±145.40% (5 runs sampled)
generateKeyPair 4096bits x 0.02 ops/sec ±96.53% (5 runs sampled)
sign and verify x 95.98 ops/sec ±1.51% (71 runs sampled)
```
##### Browser (Chrome `53.0.2785.116`)
```
generateKeyPair 1024bits x 3.56 ops/sec ±27.16% (23 runs sampled)
generateKeyPair 2048bits x 0.49 ops/sec ±69.32% (8 runs sampled)
generateKeyPair 4096bits x 0.03 ops/sec ±77.11% (5 runs sampled)
sign and verify x 109 ops/sec ±2.00% (53 runs sampled)
```
#### After
##### Node `6.6.0`
```
generateKeyPair 1024bits x 42.45 ops/sec ±9.87% (52 runs sampled)
generateKeyPair 2048bits x 7.46 ops/sec ±23.80% (16 runs sampled)
generateKeyPair 4096bits x 1.50 ops/sec ±58.59% (13 runs sampled)
sign and verify x 1,080 ops/sec ±2.23% (74 runs sampled)
```
##### Browser (Chrome `53.0.2785.116`)
```
generateKeyPair 1024bits x 5.89 ops/sec ±18.94% (19 runs sampled)
generateKeyPair 2048bits x 1.32 ops/sec ±36.84% (10 runs sampled)
generateKeyPair 4096bits x 0.20 ops/sec ±62.49% (5 runs sampled)
sign and verify x 608 ops/sec ±6.75% (56 runs sampled)
```
### Key Stretcher
#### Before
##### Node `6.6.0`
```
keyStretcher AES-128 SHA1 x 3,863 ops/sec ±3.80% (70 runs sampled)
keyStretcher AES-128 SHA256 x 3,862 ops/sec ±5.33% (64 runs sampled)
keyStretcher AES-128 SHA512 x 3,369 ops/sec ±1.73% (73 runs sampled)
keyStretcher AES-256 SHA1 x 3,008 ops/sec ±4.81% (67 runs sampled)
keyStretcher AES-256 SHA256 x 2,900 ops/sec ±7.01% (64 runs sampled)
keyStretcher AES-256 SHA512 x 2,553 ops/sec ±4.45% (73 runs sampled)
keyStretcher Blowfish SHA1 x 28,045 ops/sec ±7.32% (61 runs sampled)
keyStretcher Blowfish SHA256 x 18,860 ops/sec ±5.36% (67 runs sampled)
keyStretcher Blowfish SHA512 x 12,142 ops/sec ±12.44% (72 runs sampled)
```
##### Browser (Chrome `53.0.2785.116`)
```
keyStretcher AES-128 SHA1 x 4,168 ops/sec ±4.08% (49 runs sampled)
keyStretcher AES-128 SHA256 x 4,239 ops/sec ±6.36% (48 runs sampled)
keyStretcher AES-128 SHA512 x 3,600 ops/sec ±5.15% (51 runs sampled)
keyStretcher AES-256 SHA1 x 3,009 ops/sec ±6.82% (48 runs sampled)
keyStretcher AES-256 SHA256 x 3,086 ops/sec ±9.56% (19 runs sampled)
keyStretcher AES-256 SHA512 x 2,470 ops/sec ±2.22% (54 runs sampled)
keyStretcher Blowfish SHA1 x 7,143 ops/sec ±15.17% (9 runs sampled)
keyStretcher Blowfish SHA256 x 17,846 ops/sec ±4.74% (46 runs sampled)
keyStretcher Blowfish SHA512 x 7,726 ops/sec ±1.81% (50 runs sampled)
```
#### After
##### Node `6.6.0`
```
keyStretcher AES-128 SHA1 x 6,680 ops/sec ±3.62% (65 runs sampled)
keyStretcher AES-128 SHA256 x 8,124 ops/sec ±4.37% (66 runs sampled)
keyStretcher AES-128 SHA512 x 11,683 ops/sec ±4.56% (66 runs sampled)
keyStretcher AES-256 SHA1 x 5,531 ops/sec ±4.69% (68 runs sampled)
keyStretcher AES-256 SHA256 x 6,725 ops/sec ±4.87% (66 runs sampled)
keyStretcher AES-256 SHA512 x 9,042 ops/sec ±3.87% (64 runs sampled)
keyStretcher Blowfish SHA1 x 40,757 ops/sec ±5.38% (60 runs sampled)
keyStretcher Blowfish SHA256 x 41,845 ops/sec ±4.89% (64 runs sampled)
keyStretcher Blowfish SHA512 x 42,345 ops/sec ±4.86% (63 runs sampled)
```
##### Browser (Chrome `53.0.2785.116`)
```
keyStretcher AES-128 SHA1 x 479 ops/sec ±2.12% (54 runs sampled)
keyStretcher AES-128 SHA256 x 668 ops/sec ±2.02% (53 runs sampled)
keyStretcher AES-128 SHA512 x 1,112 ops/sec ±1.61% (54 runs sampled)
keyStretcher AES-256 SHA1 x 460 ops/sec ±1.37% (54 runs sampled)
keyStretcher AES-256 SHA256 x 596 ops/sec ±1.56% (54 runs sampled)
keyStretcher AES-256 SHA512 x 808 ops/sec ±3.27% (52 runs sampled)
keyStretcher Blowfish SHA1 x 3,015 ops/sec ±3.51% (52 runs sampled)
keyStretcher Blowfish SHA256 x 2,755 ops/sec ±3.82% (53 runs sampled)
keyStretcher Blowfish SHA512 x 2,955 ops/sec ±5.35% (51 runs sampled)
```
### Ephemeral Keys
#### Before
##### Node `6.6.0`
```
ephemeral key with secrect P-256 x 89.93 ops/sec ±39.45% (72 runs sampled)
ephemeral key with secrect P-384 x 110 ops/sec ±1.28% (71 runs sampled)
ephemeral key with secrect P-521 x 112 ops/sec ±1.70% (72 runs sampled)
```
##### Browser (Chrome `53.0.2785.116`)
```
ephemeral key with secrect P-256 x 6.27 ops/sec ±15.89% (35 runs sampled)
ephemeral key with secrect P-384 x 6.84 ops/sec ±1.21% (35 runs sampled)
ephemeral key with secrect P-521 x 6.60 ops/sec ±1.84% (34 runs sampled)
```
#### After
##### Node `6.6.0`
```
ephemeral key with secrect P-256 x 555 ops/sec ±1.61% (75 runs sampled)
ephemeral key with secrect P-384 x 547 ops/sec ±4.40% (68 runs sampled)
ephemeral key with secrect P-521 x 583 ops/sec ±4.84% (72 runs sampled)
```
##### Browser (Chrome `53.0.2785.116`)
```
ephemeral key with secrect P-256 x 796 ops/sec ±2.36% (53 runs sampled)
ephemeral key with secrect P-384 x 788 ops/sec ±2.66% (53 runs sampled)
ephemeral key with secrect P-521 x 808 ops/sec ±1.83% (54 runs sampled)
```

120
test/aes/aes.spec.js Normal file
View File

@@ -0,0 +1,120 @@
/* 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 series = require('async/series')
const Buffer = require('safe-buffer').Buffer
const crypto = require('../../src')
const fixtures = require('./../fixtures/aes')
const goFixtures = require('./../fixtures/go-aes')
const bytes = {
16: 'AES-128',
32: 'AES-256'
}
describe('AES-CTR', () => {
Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - encrypt and decrypt`, (done) => {
const key = Buffer.alloc(parseInt(byte, 10))
key.fill(5)
const iv = Buffer.alloc(16)
iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist()
series([
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher),
encryptAndDecrypt(cipher)
], done)
})
})
})
Object.keys(bytes).forEach((byte) => {
it(`${bytes[byte]} - fixed - encrypt and decrypt`, (done) => {
const key = Buffer.alloc(parseInt(byte, 10))
key.fill(5)
const iv = Buffer.alloc(16)
iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist()
series(fixtures[byte].inputs.map((rawIn, i) => (cb) => {
const input = Buffer.from(rawIn)
const output = Buffer.from(fixtures[byte].outputs[i])
cipher.encrypt(input, (err, res) => {
expect(err).to.not.exist()
expect(res).to.have.length(output.length)
expect(res).to.eql(output)
cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist()
expect(res).to.eql(input)
cb()
})
})
}), done)
})
})
})
Object.keys(bytes).forEach((byte) => {
if (!goFixtures[byte]) {
return
}
it(`${bytes[byte]} - go interop - encrypt and decrypt`, (done) => {
const key = Buffer.alloc(parseInt(byte, 10))
key.fill(5)
const iv = Buffer.alloc(16)
iv.fill(1)
crypto.aes.create(key, iv, (err, cipher) => {
expect(err).to.not.exist()
series(goFixtures[byte].inputs.map((rawIn, i) => (cb) => {
const input = Buffer.from(rawIn)
const output = Buffer.from(goFixtures[byte].outputs[i])
cipher.encrypt(input, (err, res) => {
expect(err).to.not.exist()
expect(res).to.have.length(output.length)
expect(res).to.be.eql(output)
cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist()
expect(res).to.be.eql(input)
cb()
})
})
}), done)
})
})
})
})
function encryptAndDecrypt (cipher) {
const data = Buffer.alloc(100)
data.fill(Math.ceil(Math.random() * 100))
return (cb) => {
cipher.encrypt(data, (err, res) => {
expect(err).to.not.exist()
cipher.decrypt(res, (err, res) => {
expect(err).to.not.exist()
expect(res).to.be.eql(data)
cb()
})
})
}
}

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

@@ -0,0 +1,123 @@
/* 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', () => {
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

@@ -1,44 +0,0 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const EC = require('elliptic').ec
const crypto = require('../src')
const fixtures = require('./fixtures/go-elliptic-key')
describe('generateEphemeralKeyPair', () => {
it('returns a function that generates a shared secret', () => {
const res = crypto.generateEphemeralKeyPair('P-256')
const ourPublic = '044374add0df35706db7dade25f3959fc051d2ef5166f8a6a0aa632d0ab41cdb4d30e1a064e121ac56155235a6b8d4c5d8fe35e019f507f4e2ff1445e229d7af43'
expect(
res.genSharedKey(ourPublic)
).to.have.length(32)
expect(
res.key
).to.exist
})
describe('go interop', () => {
it('generates a shared secret', () => {
const curve = fixtures.curve
const ec = new EC(fixtures.curveJs)
const bobPrivate = ec.keyFromPrivate(fixtures.bob.private, 'binary')
const alice = crypto.generateEphemeralKeyPair(curve)
const bob = {
key: fixtures.bob.public,
// this is using bobs private key from go ipfs
// instead of alices
genSharedKey: (key) => alice.genSharedKey(key, bobPrivate)
}
const s1 = alice.genSharedKey(bob.key)
const s2 = bob.genSharedKey(alice.key)
expect(s1.equals(s2)).to.be.eql(true)
})
})
})

27
test/fixtures/aes.js vendored Normal file
View File

@@ -0,0 +1,27 @@
'use strict'
const fixes16 = [
require('./fix1.json'),
require('./fix2.json'),
require('./fix3.json'),
require('./fix4.json'),
require('./fix5.json')
]
const fixes32 = [
require('./fix6.json'),
require('./fix7.json'),
require('./fix8.json'),
require('./fix9.json'),
require('./fix10.json')
]
module.exports = {
16: {
inputs: fixes16.map((f) => f.input),
outputs: fixes16.map((f) => f.output)
},
32: {
inputs: fixes32.map((f) => f.input),
outputs: fixes32.map((f) => f.output)
}
}

212
test/fixtures/fix1.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47
]
},
"output": {
"type": "Buffer",
"data": [
121,
104,
0,
151,
57,
137,
22,
239,
234,
151,
58,
15,
100,
22,
228,
110,
85,
248,
249,
15,
145,
128,
223,
25,
192,
175,
132,
169,
98,
203,
231,
106,
224,
102,
206,
244,
29,
213,
36,
2,
26,
213,
94,
29,
134,
219,
136,
73,
212,
176,
33,
95,
198,
91,
148,
139,
132,
252,
182,
115,
116,
160,
146,
194,
0,
97,
181,
0,
193,
149,
21,
51,
248,
97,
32,
62,
86,
153,
238,
67,
38,
34,
55,
143,
70,
193,
99,
107,
31,
67,
90,
97,
55,
63,
69,
203,
33,
233,
74,
237
]
}
}

212
test/fixtures/fix10.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72,
72
]
},
"output": {
"type": "Buffer",
"data": [
201,
224,
56,
64,
167,
224,
124,
49,
19,
51,
208,
226,
216,
50,
12,
73,
15,
255,
156,
108,
98,
179,
144,
110,
33,
151,
43,
64,
227,
153,
120,
39,
21,
151,
41,
61,
245,
20,
31,
23,
109,
213,
109,
55,
35,
40,
122,
109,
41,
10,
32,
176,
25,
184,
91,
176,
177,
134,
138,
252,
160,
2,
108,
43,
222,
239,
174,
2,
145,
74,
34,
131,
237,
214,
235,
102,
26,
204,
124,
64,
101,
134,
186,
45,
55,
29,
52,
55,
171,
95,
172,
86,
242,
101,
141,
153,
222,
161,
128,
83
]
}
}

212
test/fixtures/fix2.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24,
24
]
},
"output": {
"type": "Buffer",
"data": [
109,
172,
127,
179,
110,
222,
79,
219,
87,
76,
70,
204,
166,
110,
184,
229,
90,
49,
160,
252,
78,
58,
73,
51,
152,
218,
3,
200,
10,
124,
152,
117,
137,
40,
23,
127,
56,
57,
203,
31,
101,
227,
31,
198,
223,
86,
98,
120,
100,
86,
116,
144,
142,
127,
68,
175,
249,
232,
22,
83,
22,
68,
60,
230,
146,
22,
153,
193,
67,
5,
51,
253,
239,
210,
80,
31,
254,
103,
185,
145,
123,
99,
205,
175,
156,
144,
191,
67,
31,
236,
43,
98,
197,
235,
31,
50,
69,
228,
100,
64
]
}
}

212
test/fixtures/fix3.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7
]
},
"output": {
"type": "Buffer",
"data": [
191,
93,
126,
191,
180,
42,
118,
144,
28,
188,
211,
191,
211,
130,
170,
153,
134,
240,
179,
83,
75,
23,
42,
68,
158,
200,
123,
155,
57,
169,
152,
133,
33,
114,
90,
29,
131,
91,
70,
105,
83,
45,
40,
47,
77,
96,
97,
8,
40,
1,
110,
245,
106,
172,
152,
146,
5,
114,
132,
0,
179,
31,
44,
78,
19,
109,
92,
199,
226,
36,
12,
74,
180,
241,
224,
107,
83,
13,
167,
27,
251,
101,
193,
98,
49,
90,
225,
197,
75,
213,
144,
52,
235,
130,
92,
247,
219,
139,
209,
132
]
}
}

212
test/fixtures/fix4.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25,
25
]
},
"output": {
"type": "Buffer",
"data": [
191,
110,
53,
190,
250,
44,
190,
136,
22,
209,
131,
200,
112,
31,
61,
183,
247,
95,
4,
249,
69,
147,
238,
74,
18,
71,
197,
115,
141,
226,
102,
92,
91,
128,
181,
172,
67,
109,
17,
165,
52,
10,
55,
31,
55,
225,
253,
140,
154,
35,
104,
62,
119,
103,
197,
152,
125,
134,
140,
181,
170,
76,
75,
114,
195,
188,
68,
197,
28,
47,
116,
82,
34,
128,
232,
122,
14,
229,
122,
161,
36,
212,
161,
164,
145,
86,
215,
233,
222,
50,
143,
89,
131,
32,
130,
196,
109,
36,
204,
254
]
}
}

212
test/fixtures/fix5.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48
]
},
"output": {
"type": "Buffer",
"data": [
97,
142,
8,
37,
69,
173,
124,
180,
97,
70,
45,
91,
196,
126,
184,
135,
213,
104,
171,
89,
231,
63,
43,
42,
7,
245,
75,
165,
205,
182,
24,
50,
170,
217,
128,
112,
114,
215,
209,
145,
135,
235,
179,
212,
5,
81,
142,
199,
53,
221,
39,
239,
167,
21,
237,
168,
145,
249,
250,
108,
2,
247,
89,
73,
228,
227,
255,
155,
121,
157,
205,
96,
43,
32,
112,
209,
173,
96,
143,
43,
220,
140,
26,
205,
34,
34,
53,
157,
41,
167,
125,
235,
243,
85,
13,
14,
93,
109,
233,
186
]
}
}

212
test/fixtures/fix6.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68,
68
]
},
"output": {
"type": "Buffer",
"data": [
198,
59,
91,
107,
222,
214,
31,
230,
112,
1,
199,
174,
17,
224,
194,
225,
138,
65,
58,
160,
31,
249,
102,
16,
74,
46,
85,
30,
232,
249,
120,
108,
38,
165,
105,
27,
12,
98,
98,
108,
130,
163,
16,
137,
116,
104,
153,
188,
5,
251,
163,
244,
0,
58,
1,
207,
25,
78,
188,
210,
205,
221,
48,
132,
72,
209,
11,
67,
14,
42,
218,
71,
148,
252,
126,
183,
60,
32,
93,
36,
125,
103,
191,
117,
82,
241,
190,
176,
1,
129,
118,
112,
139,
153,
178,
56,
61,
91,
52,
198
]
}
}

212
test/fixtures/fix7.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10,
10
]
},
"output": {
"type": "Buffer",
"data": [
206,
241,
99,
120,
248,
163,
57,
30,
216,
86,
255,
192,
89,
193,
176,
17,
78,
62,
80,
149,
189,
235,
27,
157,
175,
248,
7,
19,
222,
64,
111,
199,
204,
163,
26,
16,
95,
221,
70,
32,
239,
4,
58,
162,
253,
237,
8,
51,
94,
3,
165,
186,
223,
210,
116,
101,
228,
82,
103,
76,
74,
44,
51,
117,
189,
140,
132,
230,
188,
243,
24,
158,
149,
93,
147,
226,
113,
195,
31,
24,
9,
19,
27,
132,
180,
152,
26,
65,
125,
144,
86,
167,
41,
144,
158,
204,
76,
46,
181,
110
]
}
}

212
test/fixtures/fix8.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75,
75
]
},
"output": {
"type": "Buffer",
"data": [
153,
161,
201,
66,
87,
46,
242,
87,
136,
238,
151,
198,
129,
122,
62,
205,
142,
252,
109,
187,
238,
183,
63,
95,
240,
97,
220,
209,
37,
144,
237,
84,
251,
149,
152,
222,
89,
200,
208,
119,
213,
38,
65,
19,
2,
252,
193,
125,
94,
76,
182,
198,
243,
121,
253,
16,
45,
254,
82,
47,
146,
206,
41,
105,
254,
237,
236,
141,
118,
214,
197,
228,
59,
125,
45,
200,
61,
24,
110,
26,
235,
92,
175,
255,
85,
119,
57,
160,
145,
107,
206,
28,
62,
10,
166,
89,
7,
20,
246,
243
]
}
}

212
test/fixtures/fix9.json vendored Normal file
View File

@@ -0,0 +1,212 @@
{
"input": {
"type": "Buffer",
"data": [
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35,
35
]
},
"output": {
"type": "Buffer",
"data": [
79,
215,
22,
29,
132,
130,
214,
248,
237,
124,
234,
54,
215,
78,
0,
211,
246,
222,
54,
91,
53,
2,
49,
40,
0,
202,
188,
25,
184,
121,
164,
235,
189,
97,
14,
0,
83,
166,
88,
62,
55,
49,
79,
153,
136,
193,
133,
206,
172,
99,
207,
73,
246,
216,
192,
107,
50,
206,
167,
242,
25,
180,
63,
184,
201,
61,
90,
242,
223,
192,
13,
140,
31,
240,
112,
157,
250,
90,
142,
3,
40,
12,
106,
63,
73,
42,
79,
82,
20,
41,
187,
173,
23,
85,
59,
253,
212,
191,
109,
46
]
}
}

20
test/fixtures/go-aes.js vendored Normal file
View File

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

View File

@@ -1,14 +1,15 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
module.exports = {
curve: 'P-256',
curveJs: 'p256',
bob: {
private: [
231, 236, 69, 16, 13, 92, 76, 83, 75, 40, 32, 71, 235, 187, 29, 214, 98, 231, 42, 5, 80, 89, 58, 175, 8, 95, 86, 50, 44, 214, 4, 172
],
public: new Buffer([
4, 160, 169, 215, 85, 152, 11, 209, 69, 105, 17, 51, 49, 83, 214, 171, 157, 73, 165, 85, 28, 196, 161, 234, 87, 149, 139, 76, 123, 37, 174, 194, 67, 167, 18, 34, 164, 35, 171, 164, 238, 141, 199, 206, 86, 130, 183, 88, 63, 121, 110, 150, 229, 10, 213, 176, 181, 1, 98, 20, 246, 85, 212, 200, 229
private: Buffer.from([
181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170
]),
public: Buffer.from([
4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90
])
}
}

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

@@ -0,0 +1,30 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
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

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

View File

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

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

@@ -0,0 +1,11 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
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')
}

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

@@ -0,0 +1,29 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const Buffer = require('safe-buffer').Buffer
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,70 +0,0 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const crypto = require('../src')
const fixtures = require('./fixtures/go-key-rsa')
describe('libp2p-crypto', () => {
let key
before(() => {
key = crypto.generateKeyPair('RSA', 2048)
})
it('marshalPublicKey and unmarshalPublicKey', () => {
const key2 = crypto.unmarshalPublicKey(crypto.marshalPublicKey(key.public))
expect(key2.equals(key.public)).to.be.eql(true)
})
it('marshalPrivateKey and unmarshalPrivateKey', () => {
const key2 = crypto.unmarshalPrivateKey(crypto.marshalPrivateKey(key))
expect(key2.equals(key)).to.be.eql(true)
})
describe('go interop', () => {
it('unmarshals private key', () => {
const key = crypto.unmarshalPrivateKey(fixtures.private.key)
const hash = fixtures.private.hash
expect(
key.hash()
).to.be.eql(
hash
)
})
it('unmarshals public key', () => {
const key = crypto.unmarshalPublicKey(fixtures.public.key)
const hash = fixtures.public.hash
expect(
key.hash()
).to.be.eql(
hash
)
})
it('unmarshal -> marshal, private key', () => {
const key = crypto.unmarshalPrivateKey(fixtures.private.key)
const marshalled = crypto.marshalPrivateKey(key)
expect(
fixtures.private.key.equals(marshalled)
).to.be.eql(
true
)
})
it('unmarshal -> marshal, public key', () => {
const key = crypto.unmarshalPublicKey(fixtures.public.key)
const marshalled = crypto.marshalPublicKey(key)
expect(
fixtures.public.key.equals(marshalled)
).to.be.eql(
true
)
})
})
})

View File

@@ -1,46 +0,0 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const crypto = require('../src')
const fixtures = require('./fixtures/go-stretch-key')
describe('keyStretcher', () => {
describe('generate', () => {
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
const hashes = ['SHA1', 'SHA256', 'SHA512']
const res = crypto.generateEphemeralKeyPair('P-256')
const secret = res.genSharedKey(res.key)
ciphers.forEach((cipher) => {
hashes.forEach((hash) => {
it(`${cipher} - ${hash}`, () => {
const keys = crypto.keyStretcher(cipher, hash, secret)
expect(keys.k1).to.exist
expect(keys.k2).to.exist
})
})
})
})
describe('go interop', () => {
fixtures.forEach((test) => {
it(`${test.cipher} - ${test.hash}`, () => {
const cipher = test.cipher
const hash = test.hash
const secret = test.secret
const keys = crypto.keyStretcher(cipher, hash, secret)
expect(keys.k1.iv).to.be.eql(test.k1.iv)
expect(keys.k1.cipherKey).to.be.eql(test.k1.cipherKey)
expect(keys.k1.macKey).to.be.eql(test.k1.macKey)
expect(keys.k2.iv).to.be.eql(test.k2.iv)
expect(keys.k2.cipherKey).to.be.eql(test.k2.cipherKey)
expect(keys.k2.macKey).to.be.eql(test.k2.macKey)
})
})
})
})

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

@@ -0,0 +1,209 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const Buffer = require('safe-buffer').Buffer
const crypto = require('../../src')
const ed25519 = crypto.keys.supportedKeys.ed25519
const fixtures = require('../fixtures/go-key-ed25519')
describe('ed25519', () => {
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('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

@@ -0,0 +1,73 @@
/* 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 parallel = require('async/parallel')
const fixtures = require('../fixtures/go-elliptic-key')
const crypto = require('../../src')
const curves = ['P-256', 'P-384'] // 'P-521' fails in tests :( no clue why
const lengths = {
'P-256': 65,
'P-384': 97,
'P-521': 133
}
const secretLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
describe('generateEphemeralKeyPair', () => {
curves.forEach((curve) => {
it(`generate and shared key ${curve}`, (done) => {
parallel([
(cb) => crypto.keys.generateEphemeralKeyPair(curve, cb),
(cb) => crypto.keys.generateEphemeralKeyPair(curve, cb)
], (err, keys) => {
expect(err).to.not.exist()
expect(keys[0].key).to.have.length(lengths[curve])
expect(keys[1].key).to.have.length(lengths[curve])
keys[0].genSharedKey(keys[1].key, (err, shared) => {
expect(err).to.not.exist()
expect(shared).to.have.length(secretLengths[curve])
done()
})
})
})
})
describe('go interop', () => {
it('generates a shared secret', (done) => {
const curve = fixtures.curve
parallel([
(cb) => crypto.keys.generateEphemeralKeyPair(curve, cb),
(cb) => crypto.keys.generateEphemeralKeyPair(curve, cb)
], (err, res) => {
expect(err).to.not.exist()
const alice = res[0]
const bob = res[1]
bob.key = fixtures.bob.public
parallel([
(cb) => alice.genSharedKey(bob.key, cb),
(cb) => bob.genSharedKey(alice.key, fixtures.bob, cb)
], (err, secrets) => {
expect(err).to.not.exist()
expect(secrets[0]).to.eql(secrets[1])
expect(secrets[0]).to.have.length(32)
done()
})
})
})
})
})

View File

@@ -0,0 +1,76 @@
/* 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-stretch-key')
describe('keyStretcher', () => {
describe('generate', () => {
const ciphers = ['AES-128', 'AES-256', 'Blowfish']
const hashes = ['SHA1', 'SHA256', 'SHA512']
let res
let secret
before((done) => {
crypto.keys.generateEphemeralKeyPair('P-256', (err, _res) => {
if (err) {
return done(err)
}
res = _res
res.genSharedKey(res.key, (err, _secret) => {
if (err) {
return done(err)
}
secret = _secret
done()
})
})
})
ciphers.forEach((cipher) => {
hashes.forEach((hash) => {
it(`${cipher} - ${hash}`, (done) => {
crypto.keys.keyStretcher(cipher, hash, secret, (err, keys) => {
if (err) {
return done(err)
}
expect(keys.k1).to.exist()
expect(keys.k2).to.exist()
done()
})
})
})
})
})
describe('go interop', () => {
fixtures.forEach((test) => {
it(`${test.cipher} - ${test.hash}`, (done) => {
const cipher = test.cipher
const hash = test.hash
const secret = test.secret
crypto.keys.keyStretcher(cipher, hash, secret, (err, keys) => {
if (err) {
return done(err)
}
expect(keys.k1.iv).to.be.eql(test.k1.iv)
expect(keys.k1.cipherKey).to.be.eql(test.k1.cipherKey)
expect(keys.k1.macKey).to.be.eql(test.k1.macKey)
expect(keys.k2.iv).to.be.eql(test.k2.iv)
expect(keys.k2.cipherKey).to.be.eql(test.k2.cipherKey)
expect(keys.k2.macKey).to.be.eql(test.k2.macKey)
done()
})
})
})
})
})

147
test/keys/rsa.spec.js Normal file
View File

@@ -0,0 +1,147 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const Buffer = require('safe-buffer').Buffer
const crypto = require('../../src')
const rsa = crypto.keys.supportedKeys.rsa
const fixtures = require('../fixtures/go-key-rsa')
describe('RSA', () => {
let key
before((done) => {
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) {
return done(err)
}
key = _key
done()
})
})
it('generates a valid key', (done) => {
expect(key).to.be.an.instanceof(rsa.RsaPrivateKey)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.have.length(34)
done()
})
})
it('signs', (done) => {
const text = key.genSecret()
key.sign(text, (err, sig) => {
if (err) {
return done(err)
}
key.public.verify(text, sig, (err, res) => {
if (err) {
return done(err)
}
expect(res).to.be.eql(true)
done()
})
})
})
it('encoding', (done) => {
const keyMarshal = key.marshal()
rsa.unmarshalRsaPrivateKey(keyMarshal, (err, key2) => {
if (err) {
return done(err)
}
const keyMarshal2 = key2.marshal()
expect(keyMarshal).to.eql(keyMarshal2)
const pk = key.public
const pkMarshal = pk.marshal()
const pk2 = rsa.unmarshalRsaPublicKey(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('RSA', 2048, (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.be.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('go interop', () => {
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) => {
if (err) throw err
expect(err).to.not.exist()
expect(ok).to.equal(true)
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()
})
})
})

View File

@@ -1,129 +0,0 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const crypto = require('../src')
const rsa = crypto.keys.rsa
describe('RSA', () => {
let key
before(() => {
key = crypto.generateKeyPair('RSA', 2048)
})
it('generates a valid key', () => {
expect(
key
).to.be.an.instanceof(
rsa.RsaPrivateKey
)
expect(
key.hash()
).to.have.length(
34
)
})
it('signs', () => {
const pk = key.public
const text = key.genSecret()
const sig = key.sign(text)
expect(
pk.verify(text, sig)
).to.be.eql(
true
)
})
it('encoding', () => {
const keyMarshal = key.marshal()
const key2 = rsa.unmarshalRsaPrivateKey(keyMarshal)
const keyMarshal2 = key2.marshal()
expect(
keyMarshal
).to.be.eql(
keyMarshal2
)
const pk = key.public
const pkMarshal = pk.marshal()
const pk2 = rsa.unmarshalRsaPublicKey(pkMarshal)
const pkMarshal2 = pk2.marshal()
expect(
pkMarshal
).to.be.eql(
pkMarshal2
)
})
describe('key equals', () => {
it('equals itself', () => {
expect(
key.equals(key)
).to.be.eql(
true
)
expect(
key.public.equals(key.public)
).to.be.eql(
true
)
})
it('not equals other key', () => {
const key2 = crypto.generateKeyPair('RSA', 2048)
expect(
key.equals(key2)
).to.be.eql(
false
)
expect(
key2.equals(key)
).to.be.eql(
false
)
expect(
key.public.equals(key2.public)
).to.be.eql(
false
)
expect(
key2.public.equals(key.public)
).to.be.eql(
false
)
})
})
it('sign and verify', () => {
const data = new Buffer('hello world')
const sig = key.sign(data)
expect(
key.public.verify(data, sig)
).to.be.eql(
true
)
})
it('does fails to verify for different data', () => {
const data = new Buffer('hello world')
const sig = key.sign(data)
expect(
key.public.verify(new Buffer('hello'), sig)
).to.be.eql(
false
)
})
})

31
test/util.spec.js Normal file
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()
})
})

29552
vendor/forge.bundle.js vendored

File diff suppressed because it is too large Load Diff