Compare commits

..

42 Commits

Author SHA1 Message Date
967594c9a3 chore: release version v0.16.2 2019-09-25 11:50:14 +02:00
03893a3795 chore: update contributors 2019-09-25 11:50:14 +02:00
50afa4efbc chore(deps): update ursa-optional 2019-09-25 11:44:47 +02:00
1c54a9b196 Merge pull request #158 from libp2p/v0.16.x-upgrade-node-forge
V0.16.x upgrade node forge
2019-09-25 11:39:07 +02:00
6f2c347895 chore: update aegir so tests run on browsers agin 2019-09-23 10:36:22 +01:00
867982ab92 chore: upgrade node-forge dep 2019-09-23 10:31:35 +01:00
7b3625888c chore: release version v0.16.1 2019-02-26 09:28:41 +01:00
b7bce77ad5 chore: update contributors 2019-02-26 09:28:41 +01:00
c1f867bd9c chore: update badges for consistency across libp2p org 2019-02-26 09:25:15 +01:00
e3f02eb6f1 chore: updates libp2p-crypto-secp256k1 2019-02-26 09:24:40 +01:00
a0874389a9 chore(ci): use travis
This PR changes Jenkins to travis for CI. In addition, 2 dependencies were missing in the `package.json` and the `dep-check` was not passing.
2019-02-20 20:57:36 +01:00
567d68c855 chore: release version v0.16.0 2019-01-08 21:33:49 +01:00
af782c5906 chore: update contributors 2019-01-08 21:33:49 +01:00
f0593c9e6d chore: update deps 2019-01-08 21:33:02 +01:00
8d8294dc3f fix: clean up, bundle size reduction
BREAKING CHANGE: getRandomValues method exported from src/keys/rsa-browser.js and src/keys/rsa.js signature has changed from accepting an array to a number for random byte length
2019-01-08 21:29:42 +01:00
df23d634c5 chore: release version v0.15.0 2019-01-03 16:15:45 +00:00
88e1bcf75f chore: update contributors 2019-01-03 16:15:45 +00:00
c54ea206f0 feat: nextTick instead of setImmediate, and fix sync in async (#136)
* fix: avoid sync callback in async function

* chore: fix linting

* chore: remove non jenkins ci

* refactor: use nextTick over setImmediate

* refactor: async/nextTick for better browser support
2019-01-03 16:13:07 +00:00
857d2bd902 chore: release version v0.14.1 2018-11-05 18:29:00 +00:00
200110cb9d chore: update contributors 2018-11-05 18:29:00 +00:00
9e5778694c fix: dont setimmediate when its not needed 2018-11-05 19:26:45 +01:00
87e8f1c86f chore: remove lint warnings 2018-11-05 19:26:45 +01:00
df75980a88 chore: update deps 2018-11-05 19:26:45 +01:00
934390acd3 chore: release version v0.14.0 2018-09-17 15:35:20 -07:00
8b80b46667 chore: update contributors 2018-09-17 15:35:20 -07:00
e8efad546f chore: update deps 2018-09-17 15:33:43 -07:00
e8cbf13d85 fix(lint): use ~ for ursa-optional version 2018-09-17 15:32:13 -07:00
c7e0409c1c fix: windows build 2018-09-17 15:32:13 -07:00
f4c00893ad test: add test for different rsa crypto libs 2018-09-17 15:32:13 -07:00
b05e77f375 feat: use ursa-optional for lightning fast key generation
The difference between ursa and ursa-optional is that ursa-optional does not cause any problems if it fails to compile
2018-09-17 15:32:13 -07:00
ad478454d8 docs: adds usage examples to AES and HMAC 2018-05-29 14:23:29 +01:00
8c69ffb20f docs: Lead maintainer (#119)
* add lead maintainer

* chore: update deps

* Update package.json
2018-05-29 14:22:48 +01:00
e689a402a3 chore: release version v0.13.0 2018-04-05 17:32:18 +01:00
4bd032a6ae chore: update contributors 2018-04-05 17:32:18 +01:00
50c61ba46e chore: update deps 2018-04-05 17:30:34 +01:00
3a90f70350 chore: release version v0.12.1 2018-02-12 09:27:25 +00:00
743c69524c chore: update contributors 2018-02-12 09:27:24 +00:00
1a347fa04c chore: update deps 2018-02-12 09:25:50 +00:00
71339e08e7 chore: release version v0.12.0 2018-01-27 10:55:54 -08:00
0ab2c2d2d6 chore: update contributors 2018-01-27 10:55:54 -08:00
cdcca5f828 feat: improve perf (#117) 2018-01-27 10:54:04 -08:00
2c0dc706b7 Merge pull request #116 from libp2p/automatic-ci-script-update
Updating CI files
2017-12-21 17:29:43 +01:00
32 changed files with 484 additions and 243 deletions

View File

@ -1,34 +0,0 @@
**/node_modules/
**/*.log
test/repo-tests*
# Logs
logs
*.log
coverage
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
build
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
test

View File

@ -1,32 +1,44 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
sudo: false
language: node_js
matrix:
cache: npm
stages:
- check
- test
- cov
node_js:
- '10'
os:
- linux
- osx
- windows
script: npx nyc -s npm run test:node -- --bail
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
jobs:
include:
- node_js: 6
env: CXX=g++-4.8
- node_js: 8
env: CXX=g++-4.8
# - node_js: stable
# env: CXX=g++-4.8
- stage: check
script:
- npx aegir commitlint --travis
- npx aegir dep-check
- npm run lint
script:
- npm run lint
- npm run test
- npm run coverage
- stage: test
name: chrome
addons:
chrome: stable
script:
- npx aegir test -t browser
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- stage: test
name: firefox
addons:
firefox: latest
script:
- npx aegir test -t browser -- --browsers FirefoxHeadless
after_success:
- npm run coverage-publish
addons:
firefox: 'latest'
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
notifications:
email: false

View File

@ -1,3 +1,84 @@
<a name="0.16.2"></a>
## [0.16.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.16.1...v0.16.2) (2019-09-25)
<a name="0.16.1"></a>
## [0.16.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.16.0...v0.16.1) (2019-02-26)
<a name="0.16.0"></a>
# [0.16.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.15.0...v0.16.0) (2019-01-08)
### Bug Fixes
* clean up, bundle size reduction ([8d8294d](https://github.com/libp2p/js-libp2p-crypto/commit/8d8294d))
### BREAKING CHANGES
* getRandomValues method exported from src/keys/rsa-browser.js and src/keys/rsa.js signature has changed from accepting an array to a number for random byte length
<a name="0.15.0"></a>
# [0.15.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.14.1...v0.15.0) (2019-01-03)
### Features
* nextTick instead of setImmediate, and fix sync in async ([#136](https://github.com/libp2p/js-libp2p-crypto/issues/136)) ([c54ea20](https://github.com/libp2p/js-libp2p-crypto/commit/c54ea20))
<a name="0.14.1"></a>
## [0.14.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.14.0...v0.14.1) (2018-11-05)
### Bug Fixes
* dont setimmediate when its not needed ([9e57786](https://github.com/libp2p/js-libp2p-crypto/commit/9e57786))
<a name="0.14.0"></a>
# [0.14.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.13.0...v0.14.0) (2018-09-17)
### Bug Fixes
* windows build ([c7e0409](https://github.com/libp2p/js-libp2p-crypto/commit/c7e0409))
* **lint:** use ~ for ursa-optional version ([e8cbf13](https://github.com/libp2p/js-libp2p-crypto/commit/e8cbf13))
### Features
* use ursa-optional for lightning fast key generation ([b05e77f](https://github.com/libp2p/js-libp2p-crypto/commit/b05e77f))
<a name="0.13.0"></a>
# [0.13.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.12.1...v0.13.0) (2018-04-05)
<a name="0.12.1"></a>
## [0.12.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.12.0...v0.12.1) (2018-02-12)
<a name="0.12.0"></a>
# [0.12.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.11.0...v0.12.0) (2018-01-27)
### Features
* improve perf ([#117](https://github.com/libp2p/js-libp2p-crypto/issues/117)) ([cdcca5f](https://github.com/libp2p/js-libp2p-crypto/commit/cdcca5f))
<a name="0.11.0"></a>
# [0.11.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.4...v0.11.0) (2017-12-20)

View File

@ -1,9 +1,8 @@
# js-libp2p-crypto
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
[![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-crypto/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-crypto?branch=master)
[![Travis CI](https://travis-ci.org/libp2p/js-libp2p-crypto.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-crypto)
[![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-crypto.svg?style=svg)](https://circleci.com/gh/libp2p/js-libp2p-crypto)
@ -16,6 +15,10 @@
This repo contains the JavaScript implementation of the crypto primitives needed for libp2p. This is based on this [go implementation](https://github.com/libp2p/go-libp2p-crypto).
## Lead Maintainer
[Friedel Ziegelmayer](https://github.com/dignifiedquire/)
## Table of Contents
- [Install](#install)
@ -58,7 +61,7 @@ This uses `CTR` mode.
- `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`
- `callback: Function`
##### `decrypt(data, callback)`
@ -70,8 +73,51 @@ This uses `CTR` mode.
- `data: Buffer`
- `callback: Function`
```
TODO: Example of using aes
```js
var crypto = require('libp2p-crypto')
// Setting up Key and IV
// A 16 bytes array, 128 Bits, AES-128 is chosen
var key128 = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
// A 16 bytes array, 128 Bits,
var IV = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
async function main () {
let decryptedMessage = 'Hello, world!'
let encryptedMessage
// Encrypting
await crypto.aes.create(key128, IV, (err, cipher) => {
if (!err) {
cipher.encrypt(Buffer.from(decryptedMessage), (err, encryptedBuffer) => {
if (!err) {
console.log(encryptedBuffer)
// prints: <Buffer 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
encryptedMessage = encryptedBuffer
}
})
}
})
// Decrypting
await crypto.aes.create(key128, IV, (err, cipher) => {
if (!err) {
cipher.decrypt(encryptedMessage, (err, decryptedBuffer) => {
if (!err) {
console.log(decryptedBuffer)
// prints: <Buffer 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
console.log(decryptedBuffer.toString('utf-8'))
// prints: Hello, world!
}
})
}
})
}
main()
```
### `crypto.hmac`
@ -91,8 +137,20 @@ Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as def
Example:
```
TODO: Example of using hmac
```js
var crypto = require('libp2p-crypto')
let hash = 'SHA1' // 'SHA256' || 'SHA512'
crypto.hmac.create(hash, Buffer.from('secret'), (err, hmac) => {
if (!err) {
hmac.digest(Buffer.from('hello world'), (err, sig) => {
if (!err) {
console.log(sig)
}
})
}
})
```
### `crypto.keys`

View File

@ -1,29 +0,0 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
version: "{build}"
environment:
matrix:
- nodejs_version: "6"
- nodejs_version: "8"
matrix:
fast_finish: true
install:
# Install Node.js
- ps: Install-Product node $env:nodejs_version
# Upgrade npm
- npm install -g npm
# Output our current versions for debugging
- node --version
- npm --version
# Install our package dependencies
- npm install
test_script:
- npm run test:node
build: off

View File

@ -1,3 +1,4 @@
/* eslint-disable no-console */
'use strict'
const Benchmark = require('benchmark')
@ -24,4 +25,4 @@ curves.forEach((curve) => {
suite
.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
.run({ async: true })

View File

@ -1,3 +1,4 @@
/* eslint-disable no-console */
'use strict'
const Benchmark = require('benchmark')
@ -24,7 +25,7 @@ async.waterfall([
suite
.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
.run({ async: true })
})
function setup (cipher, hash, secret) {

View File

@ -1,3 +1,4 @@
/* eslint-disable no-console */
'use strict'
const Benchmark = require('benchmark')
@ -39,4 +40,4 @@ suite.add('sign and verify', (d) => {
suite
.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
.run({ async: true })

2
ci/Jenkinsfile vendored
View File

@ -1,2 +0,0 @@
// Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
javascript()

View File

@ -1,15 +0,0 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
machine:
node:
version: stable
dependencies:
pre:
- google-chrome --version
- 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 install -f
- sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb
- google-chrome --version

View File

@ -1,14 +1,19 @@
{
"name": "libp2p-crypto",
"version": "0.11.0",
"version": "0.16.2",
"description": "Crypto primitives for libp2p",
"main": "src/index.js",
"leadMaintainer": "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"browser": {
"./src/hmac/index.js": "./src/hmac/index-browser.js",
"./src/keys/ecdh.js": "./src/keys/ecdh-browser.js",
"./src/aes/ciphers.js": "./src/aes/ciphers-browser.js",
"./src/keys/rsa.js": "./src/keys/rsa-browser.js"
},
"files": [
"src",
"dist"
],
"scripts": {
"lint": "aegir lint",
"build": "aegir build",
@ -19,7 +24,8 @@
"release": "aegir release",
"release-minor": "aegir release --type minor",
"release-major": "aegir release --type major",
"coverage": "aegir coverage --ignore src/keys/keys.proto.js"
"coverage": "aegir coverage --ignore src/keys/keys.proto.js",
"size": "bundlesize -f dist/index.min.js -s 139kB"
},
"keywords": [
"IPFS",
@ -27,38 +33,36 @@
"crypto",
"rsa"
],
"author": "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"license": "MIT",
"dependencies": {
"asn1.js": "^5.0.0",
"async": "^2.6.0",
"browserify-aes": "^1.1.1",
"asmcrypto.js": "^2.3.2",
"asn1.js": "^5.0.1",
"async": "^2.6.1",
"bn.js": "^4.11.8",
"browserify-aes": "^1.2.0",
"bs58": "^4.0.1",
"jsrsasign": "^8.0.4",
"iso-random-stream": "^1.1.0",
"keypair": "^1.0.1",
"libp2p-crypto-secp256k1": "~0.2.2",
"multihashing-async": "~0.4.7",
"pem-jwk": "^1.5.1",
"libp2p-crypto-secp256k1": "~0.3.0",
"multihashing-async": "~0.5.1",
"node-forge": "^0.8.5",
"pem-jwk": "^2.0.0",
"protons": "^1.0.1",
"rsa-pem-to-jwk": "^1.1.3",
"tweetnacl": "^1.0.0",
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
"ursa-optional": "~0.10.0"
},
"devDependencies": {
"aegir": "^12.3.0",
"aegir": "^20.0.0",
"benchmark": "^2.1.4",
"chai": "^4.1.2",
"chai-string": "^1.4.0",
"dirty-chai": "^2.0.1",
"pre-commit": "^1.2.2"
"bundlesize": "^0.18.0",
"chai": "^4.2.0",
"chai-string": "^1.5.0",
"dirty-chai": "^2.0.1"
},
"pre-commit": [
"lint",
"test"
],
"engines": {
"node": ">=6.0.0",
"npm": ">=3.0.0"
"node": ">=10.0.0",
"npm": ">=6.0.0"
},
"repository": {
"type": "git",
@ -69,16 +73,24 @@
},
"homepage": "https://github.com/libp2p/js-libp2p-crypto",
"contributors": [
"Alberto Elias <hi@albertoelias.me>",
"David Dias <daviddias.p@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Greenkeeper <support@greenkeeper.io>",
"Hugo Dias <hugomrdias@gmail.com>",
"Jack Kleeman <jackkleeman@gmail.com>",
"Jacob Heun <jacobheun@gmail.com>",
"Joao Santos <jrmsantos15@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"Richard Schneider <makaretu@gmail.com>",
"Tom Swindell <t.swindell@rubyx.co.uk>",
"Vasco Santos <vasco.santos@ua.pt>",
"Victor Bjelkholm <victorbjelkholm@gmail.com>",
"Yusef Napora <yusef@napora.org>",
"achingbrain <alex@achingbrain.net>",
"dignifiedquire <dignifiedquire@users.noreply.github.com>",
"greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>",
"nikuda <nikuda@gmail.com>"
]

View File

@ -1,10 +1,10 @@
'use strict'
const asm = require('asmcrypto.js')
const setImmediate = require('async/setImmediate')
const nextTick = require('async/nextTick')
exports.create = function (key, iv, callback) {
const done = (err, res) => setImmediate(() => callback(err, res))
const done = (err, res) => nextTick(() => callback(err, res))
if (key.length !== 16 && key.length !== 32) {
return done(new Error('Invalid key length'))
@ -21,7 +21,7 @@ exports.create = function (key, iv, callback) {
const res = {
encrypt (data, cb) {
const done = (err, res) => setImmediate(() => cb(err, res))
const done = (err, res) => nextTick(() => cb(err, res))
let res
try {
@ -36,7 +36,7 @@ exports.create = function (key, iv, callback) {
},
decrypt (data, cb) {
const done = (err, res) => setImmediate(() => cb(err, res))
const done = (err, res) => nextTick(() => cb(err, res))
let res
try {

View File

@ -2,7 +2,7 @@
const nodeify = require('../nodeify')
const crypto = require('../webcrypto.js')()
const crypto = require('../webcrypto')
const lengths = require('./lengths')
const hashTypes = {
@ -12,7 +12,7 @@ const hashTypes = {
}
const sign = (key, data, cb) => {
nodeify(crypto.subtle.sign({name: 'HMAC'}, key, data)
nodeify(crypto.subtle.sign({ name: 'HMAC' }, key, data)
.then((raw) => Buffer.from(raw)), cb)
}
@ -24,7 +24,7 @@ exports.create = function (hashType, secret, callback) {
secret,
{
name: 'HMAC',
hash: {name: hash}
hash: { name: hash }
},
false,
['sign']

View File

@ -2,6 +2,7 @@
const crypto = require('crypto')
const lengths = require('./lengths')
const nextTick = require('async/nextTick')
exports.create = function (hash, secret, callback) {
const res = {
@ -10,7 +11,7 @@ exports.create = function (hash, secret, callback) {
hmac.update(data)
setImmediate(() => {
nextTick(() => {
cb(null, hmac.digest())
})
},

View File

@ -1,6 +1,6 @@
'use strict'
const webcrypto = require('../webcrypto.js')()
const webcrypto = require('../webcrypto')
const nodeify = require('../nodeify')
const BN = require('asn1.js').bignum

View File

@ -1,7 +1,7 @@
'use strict'
const crypto = require('crypto')
const setImmediate = require('async/setImmediate')
const nextTick = require('async/nextTick')
const curves = {
'P-256': 'prime256v1',
@ -16,7 +16,7 @@ exports.generateEphmeralKeyPair = function (curve, callback) {
const ecdh = crypto.createECDH(curves[curve])
ecdh.generateKeys()
setImmediate(() => callback(null, {
nextTick(() => callback(null, {
key: ecdh.getPublicKey(),
genSharedKey (theirPub, forcePrivate, cb) {
if (typeof forcePrivate === 'function') {
@ -35,7 +35,7 @@ exports.generateEphmeralKeyPair = function (curve, callback) {
return cb(err)
}
setImmediate(() => cb(null, secret))
nextTick(() => cb(null, secret))
}
}))
}

View File

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

View File

@ -2,8 +2,10 @@
const protobuf = require('protons')
const keysPBM = protobuf(require('./keys.proto'))
const jsrsasign = require('jsrsasign')
const KEYUTIL = jsrsasign.KEYUTIL
require('node-forge/lib/asn1')
require('node-forge/lib/rsa')
require('node-forge/lib/pbe')
const forge = require('node-forge/lib/forge')
exports = module.exports
@ -26,7 +28,7 @@ exports.generateEphemeralKeyPair = require('./ephemeral-keys')
// Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits, cb) => {
let key = supportedKeys[type.toLowerCase()]
const key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
@ -38,7 +40,7 @@ exports.generateKeyPair = (type, 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()]
const key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
}
@ -120,13 +122,13 @@ exports.marshalPrivateKey = (key, type) => {
exports.import = (pem, password, callback) => {
try {
const key = KEYUTIL.getKey(pem, password)
if (key instanceof jsrsasign.RSAKey) {
const jwk = KEYUTIL.getJWKFromKey(key)
return supportedKeys.rsa.fromJwk(jwk, callback)
} else {
throw new Error(`Unknown key type '${key.prototype.toString()}'`)
const key = forge.pki.decryptRsaPrivateKey(pem, password)
if (key === null) {
throw new Error('Cannot read the key, most likely the password is wrong or not a RSA key')
}
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
der = Buffer.from(der.getBytes(), 'binary')
return supportedKeys.rsa.unmarshalRsaPrivateKey(der, callback)
} catch (err) {
callback(err)
}

View File

@ -47,7 +47,7 @@ module.exports = (cipherType, hash, secret, callback) => {
return callback(err)
}
let result = []
const result = []
let j = 0
whilst(

View File

@ -1,8 +1,8 @@
'use strict'
const nodeify = require('../nodeify')
const webcrypto = require('../webcrypto.js')()
const webcrypto = require('../webcrypto')
const randomBytes = require('../random-bytes')
exports.utils = require('./rsa-utils')
@ -12,7 +12,7 @@ exports.generateKey = function (bits, callback) {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: 'SHA-256'}
hash: { name: 'SHA-256' }
},
true,
['sign', 'verify']
@ -31,7 +31,7 @@ exports.unmarshalPrivateKey = function (key, callback) {
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
hash: { name: 'SHA-256' }
},
true,
['sign']
@ -49,9 +49,7 @@ exports.unmarshalPrivateKey = function (key, callback) {
})), callback)
}
exports.getRandomValues = function (arr) {
return Buffer.from(webcrypto.getRandomValues(arr))
}
exports.getRandomValues = randomBytes
exports.hashAndSign = function (key, msg, callback) {
nodeify(webcrypto.subtle.importKey(
@ -59,13 +57,13 @@ exports.hashAndSign = function (key, msg, callback) {
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
hash: { name: 'SHA-256' }
},
false,
['sign']
).then((privateKey) => {
return webcrypto.subtle.sign(
{name: 'RSASSA-PKCS1-v1_5'},
{ name: 'RSASSA-PKCS1-v1_5' },
privateKey,
Uint8Array.from(msg)
)
@ -78,13 +76,13 @@ exports.hashAndVerify = function (key, sig, msg, callback) {
key,
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
hash: { name: 'SHA-256' }
},
false,
['verify']
).then((publicKey) => {
return webcrypto.subtle.verify(
{name: 'RSASSA-PKCS1-v1_5'},
{ name: 'RSASSA-PKCS1-v1_5' },
publicKey,
sig,
msg
@ -109,7 +107,7 @@ function derivePublicFromPrivate (jwKey) {
},
{
name: 'RSASSA-PKCS1-v1_5',
hash: {name: 'SHA-256'}
hash: { name: 'SHA-256' }
},
true,
['verify']

View File

@ -3,11 +3,13 @@
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const bs58 = require('bs58')
const nextTick = require('async/nextTick')
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
const KEYUTIL = require('jsrsasign').KEYUTIL
const setImmediate = require('async/setImmediate')
require('node-forge/lib/sha512')
require('node-forge/lib/pbe')
const forge = require('node-forge/lib/forge')
class RsaPublicKey {
constructor (key) {
@ -53,7 +55,7 @@ class RsaPrivateKey {
}
genSecret () {
return crypto.getRandomValues(new Uint8Array(16))
return crypto.getRandomValues(16)
}
sign (message, callback) {
@ -127,20 +129,28 @@ class RsaPrivateKey {
format = 'pkcs-8'
}
setImmediate(() => {
ensure(callback)
ensure(callback)
nextTick(() => {
let err = null
let pem = null
try {
const key = KEYUTIL.getKey(this._key) // _key is a JWK (JSON Web Key)
const buffer = new forge.util.ByteBuffer(this.marshal())
const asn1 = forge.asn1.fromDer(buffer)
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
if (format === 'pkcs-8') {
pem = KEYUTIL.getPEM(key, 'PKCS8PRV', password)
const options = {
algorithm: 'aes256',
count: 10000,
saltSize: 128 / 8,
prfAlgorithm: 'sha512'
}
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
} else {
err = new Error(`Unknown export format '${format}'`)
}
} catch (e) {
err = e
} catch (_err) {
err = _err
}
callback(err, pem)
@ -150,6 +160,7 @@ class RsaPrivateKey {
function unmarshalRsaPrivateKey (bytes, callback) {
const jwk = crypto.utils.pkcs1ToJwk(bytes)
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
@ -175,18 +186,18 @@ function fromJwk (jwk, callback) {
})
}
function generateKeyPair (bits, cb) {
function generateKeyPair (bits, callback) {
crypto.generateKey(bits, (err, keys) => {
if (err) {
return cb(err)
return callback(err)
}
cb(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
}
function ensure (cb) {
if (typeof cb !== 'function') {
function ensure (callback) {
if (typeof callback !== 'function') {
throw new Error('callback is required')
}
}

View File

@ -1,15 +1,37 @@
'use strict'
const crypto = require('crypto')
const keypair = require('keypair')
const setImmediate = require('async/setImmediate')
const randomBytes = require('../random-bytes')
const nextTick = require('async/nextTick')
let keypair
try {
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'keypair') {
throw new Error('Force keypair usage')
}
const ursa = require('ursa-optional') // throws if not compiled
keypair = ({ bits }) => {
const key = ursa.generatePrivateKey(bits)
return {
private: key.toPrivatePem(),
public: key.toPublicPem()
}
}
} catch (e) {
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'ursa') {
throw e
}
keypair = require('keypair')
}
const pemToJwk = require('pem-jwk').pem2jwk
const jwkToPem = require('pem-jwk').jwk2pem
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
setImmediate(() => {
nextTick(() => {
let result
try {
const key = keypair({ bits: bits })
@ -27,7 +49,7 @@ exports.generateKey = function (bits, callback) {
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
setImmediate(() => {
nextTick(() => {
if (!key) {
return callback(new Error('Key is invalid'))
}
@ -42,12 +64,10 @@ exports.unmarshalPrivateKey = function (key, callback) {
})
}
exports.getRandomValues = function (arr) {
return crypto.randomBytes(arr.length)
}
exports.getRandomValues = randomBytes
exports.hashAndSign = function (key, msg, callback) {
setImmediate(() => {
nextTick(() => {
let result
try {
const sign = crypto.createSign('RSA-SHA256')
@ -63,7 +83,7 @@ exports.hashAndSign = function (key, msg, callback) {
}
exports.hashAndVerify = function (key, sig, msg, callback) {
setImmediate(() => {
nextTick(() => {
let result
try {
const verify = crypto.createVerify('RSA-SHA256')

View File

@ -1,18 +1,19 @@
'use strict'
const crypto = require('jsrsasign').CryptoJS
const forgePbkdf2 = require('node-forge/lib/pbkdf2')
const forgeUtil = require('node-forge/lib/util')
/**
* Maps an IPFS hash name to its jsrsasign equivalent.
* Maps an IPFS hash name to its node-forge equivalent.
*
* See https://github.com/multiformats/multihash/blob/master/hashtable.csv
*
* @private
*/
const hashName = {
sha1: crypto.algo.SHA1,
'sha2-256': crypto.algo.SHA256,
'sha2-512': crypto.algo.SHA512
sha1: 'sha1',
'sha2-256': 'sha256',
'sha2-512': 'sha512'
}
/**
@ -26,16 +27,17 @@ const hashName = {
* @returns {string} - A new password
*/
function pbkdf2 (password, salt, iterations, keySize, hash) {
const opts = {
iterations: iterations,
keySize: keySize / 4, // convert bytes to words (32 bits)
hasher: hashName[hash]
}
if (!opts.hasher) {
const hasher = hashName[hash]
if (!hasher) {
throw new Error(`Hash '${hash}' is unknown or not supported`)
}
const words = crypto.PBKDF2(password, salt, opts)
return crypto.enc.Base64.stringify(words)
const dek = forgePbkdf2(
password,
salt,
iterations,
keySize,
hasher)
return forgeUtil.encode64(dek)
}
module.exports = pbkdf2

View File

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

View File

@ -6,7 +6,7 @@ const BN = require('asn1.js').bignum
// 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')
const s = bn.toArrayLike(Buffer, 'be', len).toString('base64')
return s
.replace(/(=*)$/, '') // Remove any trailing '='s

View File

@ -2,15 +2,4 @@
'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')
}
module.exports = self.crypto || self.msCrypto

View File

@ -13,7 +13,7 @@ describe('libp2p-crypto', function () {
this.timeout(20 * 1000)
let key
before((done) => {
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
crypto.keys.generateKeyPair('RSA', 512, (err, _key) => {
if (err) {
return done(err)
}

View File

@ -19,7 +19,7 @@ function doTests (fncName, fnc, num, skipBuffersAndStrings) {
// skip this garbage because it's a buffer or a string and we were told do do that
return
}
let args = []
const args = []
for (let i = 0; i < num; i++) {
args.push(garbage)
}

View File

@ -0,0 +1,65 @@
'use strict'
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
chai.use(require('chai-string'))
const LIBS = ['ursa', 'keypair']
describe('RSA crypto libs', function () {
this.timeout(20 * 1000)
LIBS.forEach(lib => {
describe(lib, () => {
let crypto
let rsa
before(() => {
process.env.LP2P_FORCE_CRYPTO_LIB = lib
for (const path in require.cache) { // clear module cache
if (path.endsWith('.js')) {
delete require.cache[path]
}
}
crypto = require('../../src')
rsa = crypto.keys.supportedKeys.rsa
})
it('generates a valid key', (done) => {
crypto.keys.generateKeyPair('RSA', 512, (err, key) => {
if (err) {
return done(err)
}
expect(key).to.be.an.instanceof(rsa.RsaPrivateKey)
key.hash((err, digest) => {
if (err) {
return done(err)
}
expect(digest).to.have.length(34)
done()
})
})
})
after(() => {
for (const path in require.cache) { // clear module cache
if (path.endsWith('.js')) {
delete require.cache[path]
}
}
delete process.env.LP2P_FORCE_CRYPTO_LIB
})
})
})
})

View File

@ -19,7 +19,7 @@ describe('RSA', function () {
let key
before((done) => {
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
crypto.keys.generateKeyPair('RSA', 512, (err, _key) => {
if (err) {
return done(err)
}
@ -97,7 +97,7 @@ describe('RSA', function () {
})
it('not equals other key', (done) => {
crypto.keys.generateKeyPair('RSA', 2048, (err, key2) => {
crypto.keys.generateKeyPair('RSA', 512, (err, key2) => {
if (err) {
return done(err)
}
@ -297,8 +297,42 @@ mBdkD5r+ixWF174naw53L8U9wF8kiK7pIE1N9TR4USEeovLwX6Ni/2MMDZedOfof
})
})
// AssertionError: expected 'this only supports TripleDES' to not exist
it.skip('can read a private encrypted key (v2 aes-256-cbc)', (done) => {
it('can read a private encrypted key (v2 aes-128-cbc)', (done) => {
/*
* Generated with
* openssl genpkey -algorithm RSA
* -pkeyopt rsa_keygen_bits:1024
* -pkeyopt rsa_keygen_pubexp:65537
* -out foo.pem
* openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword
*/
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP5QK2RfqUl4CAggA
MB0GCWCGSAFlAwQBAgQQj3OyM9gnW2dd/eRHkxjGrgSCAoCpM5GZB0v27cxzZsGc
O4/xqgwB0c/bSJ6QogtYU2KVoc7ZNQ5q9jtzn3I4ONvneOkpm9arzYz0FWnJi2C3
BPiF0D1NkfvjvMLv56bwiG2A1oBECacyAb2pXYeJY7SdtYKvcbgs3jx65uCm6TF2
BylteH+n1ewTQN9DLfASp1n81Ajq9lQGaK03SN2MUtcAPp7N9gnxJrlmDGeqlPRs
KpQYRcot+kE6Ew8a5jAr7mAxwpqvr3SM4dMvADZmRQsM4Uc/9+YMUdI52DG87EWc
0OUB+fnQ8jw4DZgOE9KKM5/QTWc3aEw/dzXr/YJsrv01oLazhqVHnEMG0Nfr0+DP
q+qac1AsCsOb71VxaRlRZcVEkEfAq3gidSPD93qmlDrCnmLYTilcLanXUepda7ez
qhjkHtpwBLN5xRZxOn3oUuLGjk8VRwfmFX+RIMYCyihjdmbEDYpNUVkQVYFGi/F/
1hxOyl9yhGdL0hb9pKHH10GGIgoqo4jSTLlb4ennihGMHCjehAjLdx/GKJkOWShy
V9hj8rAuYnRNb+tUW7ChXm1nLq14x9x1tX0ciVVn3ap/NoMkbFTr8M3pJ4bQlpAn
wCT2erYqwQtgSpOJcrFeph9TjIrNRVE7Zlmr7vayJrB/8/oPssVdhf82TXkna4fB
PcmO0YWLa117rfdeNM/Duy0ThSdTl39Qd+4FxqRZiHjbt+l0iSa/nOjTv1TZ/QqF
wqrO6EtcM45fbFJ1Y79o2ptC2D6MB4HKJq9WCt064/8zQCVx3XPbb3X8Z5o/6koy
ePGbz+UtSb9xczvqpRCOiFLh2MG1dUgWuHazjOtUcVWvilKnkjCMzZ9s1qG0sUDj
nPyn
-----END ENCRYPTED PRIVATE KEY-----
`
crypto.keys.import(pem, 'mypassword', (err, key) => {
expect(err).to.not.exist()
expect(key).to.exist()
done()
})
})
it('can read a private encrypted key (v2 aes-256-cbc)', (done) => {
/*
* Generated with
* openssl genpkey -algorithm RSA
@ -333,6 +367,40 @@ DQd8
})
})
it('can read a private encrypted key (v2 des)', (done) => {
/*
* Generated with
* openssl genpkey -algorithm RSA
* -pkeyopt rsa_keygen_bits:1024
* -pkeyopt rsa_keygen_pubexp:65537
* -out foo.pem
* openssl pkcs8 -in foo.pem -topk8 -v2 des -passout pass:mypassword
*/
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICwzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQI0lXp62ozXvwCAggA
MBEGBSsOAwIHBAiR3Id5vH0u4wSCAoDQQYOrrkPFPIa0S5fQGXnJw1F/66g92Gs1
TkGydn4ouabWb++Vbi2chee1oyZsN2l8YNzDi0Gb2PfjsGpg2aJk0a3/efgA0u6T
leEH1dA/7Hr9NVspgHkaXpHt3X6wdbznLYJeAelfj7sDXpOkULGWCkCst0Txb6bi
Oxv4c0yYykiuUrp+2xvHbF9c2PrcDb58u/OBZcCg3QB1gTugQKM+ZIBRhcTEFLrm
8gWbzBfwYiUm6aJce4zoafP0NSlEOBbpbr73A08Q1IK6pISwltOUhhTvspSZnK41
y2CHt5Drnpl1pfOw9Q0svO3VrUP+omxP1SFP17ZfaRGw2uHd08HJZs438x5dIQoH
QgjlZ8A5rcT3FjnytSh3fln2ZxAGuObghuzmOEL/+8fkGER9QVjmQlsL6OMfB4j4
ZAkLf74uaTdegF3SqDQaGUwWgk7LyualmUXWTBoeP9kRIsRQLGzAEmd6duBPypED
HhKXP/ZFA1kVp3x1fzJ2llMFB3m1JBwy4PiohqrIJoR+YvKUvzVQtbOjxtCEAj87
JFnlQj0wjTd6lfNn+okewMNjKINZx+08ui7XANNU/l18lHIIz3ssXJSmqMW+hRZ9
9oB2tntLrnRMhkVZDVHadq7eMFOPu0rkekuaZm9CO2vu4V7Qa2h+gOoeczYza0H7
A+qCKbprxyL8SKI5vug2hE+mfC1leXVRtUYm1DnE+oet99bFd0fN20NwTw0rOeRg
0Z+/ZpQNizrXxfd3sU7zaJypWCxZ6TD/U/AKBtcb2gqmUjObZhbfbWq6jU2Ye//w
EBqQkwAUXR1tNekF8CWLOrfC/wbLRxVRkayb8bQUfdgukLpz0bgw
-----END ENCRYPTED PRIVATE KEY-----
`
crypto.keys.import(pem, 'mypassword', (err, key) => {
expect(err).to.not.exist()
expect(key).to.exist()
done()
})
})
it('can read a private encrypted key (v2 des3)', (done) => {
/*
* Generated with

3
test/node.js Normal file
View File

@ -0,0 +1,3 @@
'use strict'
require('./keys/rsa-crypto-libs')

View File

@ -24,7 +24,7 @@ describe('Util', () => {
})
it('toBase64 zero padding', (done) => {
let bnpad = new BN('ff', 16)
const bnpad = new BN('ff', 16)
expect(util.toBase64(bnpad, 2)).to.eql('AP8')
done()
})