Compare commits

..

33 Commits

Author SHA1 Message Date
Victor Bjelkholm
21d4c8b74e Updating CI files
This commit updates all CI scripts to the latest version
2017-12-21 17:20:14 +01:00
David Dias
285b6ca392 chore: release version v0.11.0 2017-12-20 08:12:56 +00:00
David Dias
7d96dd3243 chore: update contributors 2017-12-20 08:12:56 +00:00
Richard Schneider
b3421284f9 feat: key exchange with jsrsasign (#115)
* feat: export/import password protected RSA key

* docs: crypto.key.import

* test: import with wrong password

* fix: lint

* test: importing openssl keys

* just to trigger circle with new ubuntu

* feat: get the RSA key id

* feat: get the ED 25519 key id

* feat: pbkdf2

* fix(pbkdf2): base64 has more chars to guess than hex

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

* fix: Fix some failing tests

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

* tests: increased timeout for test timing out in CI

* tests: increasing test timeout to please the CI gods

* tests: increasing test timeout to please the CI gods

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

* chore: update gitignore

* chore: update CI

* chore: update deps
2017-09-03 12:18:18 +01:00
Friedel Ziegelmayer
f20267b962 feat: skip nextTick in nodeify (#103) 2017-08-17 06:38:26 +02:00
David Dias
1b6a070fa8 chore: release version v0.9.4 2017-07-22 13:26:07 -07:00
David Dias
1471e07bf9 chore: update contributors 2017-07-22 13:26:06 -07:00
David Dias
bc554d1407 fix: circular circular dep -> DI 2017-07-22 13:25:15 -07:00
David Dias
83d2d52205 chore: release version v0.9.3 2017-07-22 12:36:06 -07:00
David Dias
301c779f49 chore: update contributors 2017-07-22 12:36:06 -07:00
David Dias
d552fd423a chore: use ~ instead of ^ 2017-07-22 12:33:24 -07:00
David Dias
306504c386 chore: release version v0.9.2 2017-07-22 12:23:30 -07:00
David Dias
bf80e8e511 chore: update contributors 2017-07-22 12:23:29 -07:00
David Dias
4e619e60f5 chore: update deps 2017-07-22 12:21:55 -07:00
41 changed files with 873 additions and 175 deletions

1
.eslintignore Normal file
View File

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

13
.gitignore vendored
View File

@@ -1,6 +1,11 @@
docs
package-lock.json
yarn.lock
**/node_modules/
**/*.log
test/repo-tests*
**/bundle.js
# Logs
logs
@@ -31,4 +36,12 @@ build
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
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,22 +1,19 @@
# 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:
include:
- node_js: 4
env: CXX=g++-4.8
- node_js: 6
env: CXX=g++-4.8
- node_js: stable
- node_js: 8
env: CXX=g++-4.8
# Make sure we have new NPM.
before_install:
- npm install -g npm@4
# - node_js: stable
# env: CXX=g++-4.8
script:
- npm run lint
- npm test
- npm run test
- npm run coverage
before_script:

View File

@@ -1,3 +1,89 @@
<a name="0.11.0"></a>
# [0.11.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.4...v0.11.0) (2017-12-20)
### Features
* key exchange with jsrsasign ([#115](https://github.com/libp2p/js-libp2p-crypto/issues/115)) ([b342128](https://github.com/libp2p/js-libp2p-crypto/commit/b342128))
<a name="0.10.4"></a>
## [0.10.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.3...v0.10.4) (2017-12-01)
### Bug Fixes
* catch error when unmarshaling instead of crashing ([#113](https://github.com/libp2p/js-libp2p-crypto/issues/113)) ([7608fdd](https://github.com/libp2p/js-libp2p-crypto/commit/7608fdd))
<a name="0.10.3"></a>
## [0.10.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.2...v0.10.3) (2017-09-07)
### Features
* switch protocol-buffers to protons ([#110](https://github.com/libp2p/js-libp2p-crypto/issues/110)) ([3a91ae2](https://github.com/libp2p/js-libp2p-crypto/commit/3a91ae2))
<a name="0.10.2"></a>
## [0.10.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.1...v0.10.2) (2017-09-06)
### Bug Fixes
* use regular protocol-buffers until protobufjs is fixed ([#109](https://github.com/libp2p/js-libp2p-crypto/issues/109)) ([957fdd3](https://github.com/libp2p/js-libp2p-crypto/commit/957fdd3))
### Features
* **deps:** upgrade to aegir@12 and browserify-aes@1.0.8 ([83257bc](https://github.com/libp2p/js-libp2p-crypto/commit/83257bc))
<a name="0.10.1"></a>
## [0.10.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.10.0...v0.10.1) (2017-09-05)
### Bug Fixes
* switch to protobufjs ([#107](https://github.com/libp2p/js-libp2p-crypto/issues/107)) ([dc2793f](https://github.com/libp2p/js-libp2p-crypto/commit/dc2793f))
<a name="0.10.0"></a>
# [0.10.0](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.4...v0.10.0) (2017-09-03)
### Features
* p2p addrs situation ([#106](https://github.com/libp2p/js-libp2p-crypto/issues/106)) ([9e977c7](https://github.com/libp2p/js-libp2p-crypto/commit/9e977c7))
* skip nextTick in nodeify ([#103](https://github.com/libp2p/js-libp2p-crypto/issues/103)) ([f20267b](https://github.com/libp2p/js-libp2p-crypto/commit/f20267b))
<a name="0.9.4"></a>
## [0.9.4](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.3...v0.9.4) (2017-07-22)
### Bug Fixes
* circular circular dep -> DI ([bc554d1](https://github.com/libp2p/js-libp2p-crypto/commit/bc554d1))
<a name="0.9.3"></a>
## [0.9.3](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.2...v0.9.3) (2017-07-22)
<a name="0.9.2"></a>
## [0.9.2](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.1...v0.9.2) (2017-07-22)
<a name="0.9.1"></a>
## [0.9.1](https://github.com/libp2p/js-libp2p-crypto/compare/v0.9.0...v0.9.1) (2017-07-22)

View File

@@ -10,7 +10,7 @@
[![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%3D4.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
@@ -35,6 +35,7 @@ This repo contains the JavaScript implementation of the crypto primitives needed
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
- [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback)
- [`import(pem, password, callback)`](#importpem-password-callback)
- [`webcrypto`](#webcrypto)
- [Contribute](#contribute)
- [License](#license)
@@ -183,12 +184,30 @@ Converts a private key object into a protobuf serialized private key.
Converts a protobuf serialized private key into its representative object.
### `crypto.keys.import(pem, password, callback)`
- `pem: string`
- `password: string`
- `callback: Function`
Converts a PEM password protected private key into its representative object.
### `crypto.randomBytes(number)`
- `number: Number`
Generates a Buffer with length `number` populated by random bytes.
### `crypto.pbkdf2(password, salt, iterations, keySize, hash)`
- `password: String`
- `salt: String`
- `iterations: Number`
- `keySize: Number` in bytes
- `hash: String` the hashing algorithm ('sha1', 'sha2-512', ...)
Computes the Password Based Key Derivation Function 2; returning a new password.
## Contribute
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)!
@@ -199,4 +218,4 @@ This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/c
## License
[MIT](LICENSE)
[MIT](./LICENSE)

29
appveyor.yml Normal file
View File

@@ -0,0 +1,29 @@
# 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

@@ -22,5 +22,6 @@ curves.forEach((curve) => {
}, { defer: true })
})
suite.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
suite
.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})

View File

@@ -22,8 +22,9 @@ async.waterfall([
setup(cipher, hash, secret)
}))
suite.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
suite
.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
})
function setup (cipher, hash, secret) {

View File

@@ -37,5 +37,6 @@ suite.add('sign and verify', (d) => {
defer: true
})
suite.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})
suite
.on('cycle', (event) => console.log(String(event.target)))
.run({async: true})

2
ci/Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,2 @@
// 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,3 +1,4 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "libp2p-crypto",
"version": "0.9.1",
"version": "0.11.0",
"description": "Crypto primitives for libp2p",
"main": "src/index.js",
"browser": {
@@ -10,16 +10,16 @@
"./src/keys/rsa.js": "./src/keys/rsa-browser.js"
},
"scripts": {
"lint": "aegir-lint",
"build": "aegir-build",
"test": "aegir-test",
"test:node": "aegir-test --env node",
"test:browser": "aegir-test --env browser",
"release": "aegir-release",
"release-minor": "aegir-release --type minor",
"release-major": "aegir-release --type major",
"coverage": "aegir-coverage",
"coverage-publish": "aegir-coverage publish"
"lint": "aegir lint",
"build": "aegir build",
"build-proto": "pbjs --wrap commonjs --target static-module src/keys/keys.proto > src/keys/keys.proto.js",
"test": "aegir test",
"test:node": "aegir test -t node",
"test:browser": "aegir test -t browser -t webworker",
"release": "aegir release",
"release-minor": "aegir release --type minor",
"release-major": "aegir release --type major",
"coverage": "aegir coverage --ignore src/keys/keys.proto.js"
},
"keywords": [
"IPFS",
@@ -30,24 +30,25 @@
"author": "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"license": "MIT",
"dependencies": {
"asn1.js": "^4.9.1",
"async": "^2.5.0",
"browserify-aes": "^1.0.6",
"asn1.js": "^5.0.0",
"async": "^2.6.0",
"browserify-aes": "^1.1.1",
"bs58": "^4.0.1",
"jsrsasign": "^8.0.4",
"keypair": "^1.0.1",
"libp2p-crypto-secp256k1": "^0.2.0",
"nodeify": "^1.0.1",
"libp2p-crypto-secp256k1": "~0.2.2",
"multihashing-async": "~0.4.7",
"pem-jwk": "^1.5.1",
"protocol-buffers": "^3.2.1",
"protons": "^1.0.1",
"rsa-pem-to-jwk": "^1.1.3",
"safe-buffer": "^5.1.1",
"tweetnacl": "^1.0.0",
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master",
"multihashing-async": "~0.4.6"
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
},
"devDependencies": {
"aegir": "^11.0.2",
"aegir": "^12.3.0",
"benchmark": "^2.1.4",
"chai": "^4.1.0",
"chai": "^4.1.2",
"chai-string": "^1.4.0",
"dirty-chai": "^2.0.1",
"pre-commit": "^1.2.2"
},
@@ -56,7 +57,7 @@
"test"
],
"engines": {
"node": ">=4.0.0",
"node": ">=6.0.0",
"npm": ">=3.0.0"
},
"repository": {
@@ -73,10 +74,12 @@
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Greenkeeper <support@greenkeeper.io>",
"Jack Kleeman <jackkleeman@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"Richard Schneider <makaretu@gmail.com>",
"Tom Swindell <t.swindell@rubyx.co.uk>",
"Yusef Napora <yusef@napora.org>",
"greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>",
"nikuda <nikuda@gmail.com>"
]
}
}

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

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

View File

@@ -1,7 +1,6 @@
'use strict'
const nodeify = require('nodeify')
const Buffer = require('safe-buffer').Buffer
const nodeify = require('../nodeify')
const crypto = require('../webcrypto.js')()
const lengths = require('./lengths')
@@ -12,6 +11,11 @@ const hashTypes = {
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]
@@ -27,8 +31,7 @@ exports.create = function (hashType, secret, callback) {
).then((key) => {
return {
digest (data, cb) {
nodeify(crypto.subtle.sign({name: 'HMAC'}, key, data)
.then((raw) => Buffer.from(raw)), cb)
sign(key, data, cb)
},
length: lengths[hashType]
}

View File

@@ -3,18 +3,11 @@
const hmac = require('./hmac')
const aes = require('./aes')
const keys = require('./keys')
const rsa = require('./keys/rsa')
exports = module.exports
exports.aes = aes
exports.hmac = hmac
exports.keys = keys
exports.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))
}
exports.randomBytes = require('./random-bytes')
exports.pbkdf2 = require('./pbkdf2')

View File

@@ -1,9 +1,8 @@
'use strict'
const webcrypto = require('../webcrypto.js')()
const nodeify = require('nodeify')
const nodeify = require('../nodeify')
const BN = require('asn1.js').bignum
const Buffer = require('safe-buffer').Buffer
const util = require('../util')
const toBase64 = util.toBase64

View File

@@ -1,8 +1,8 @@
'use strict'
const multihashing = require('multihashing-async')
const protobuf = require('protocol-buffers')
const Buffer = require('safe-buffer').Buffer
const protobuf = require('protons')
const bs58 = require('bs58')
const crypto = require('./ed25519')
const pbm = protobuf(require('./keys.proto'))
@@ -78,6 +78,25 @@ class Ed25519PrivateKey {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @param {function(Error, id)} callback
* @returns {undefined}
*/
id (callback) {
this.public.hash((err, hash) => {
if (err) {
return callback(err)
}
callback(null, bs58.encode(hash))
})
}
}
function unmarshalEd25519PrivateKey (bytes, callback) {

View File

@@ -2,36 +2,33 @@
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)
setImmediate(() => {
let result
try {
result = nacl.sign.keyPair()
} catch (err) {
return callback(err)
}
callback(null, result)
})
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)
setImmediate(() => {
let result
try {
result = nacl.sign.keyPair.fromSeed(seed)
} catch (err) {
return callback(err)
}
callback(null, result)
})
}
exports.hashAndSign = function (key, msg, callback) {
@@ -42,6 +39,13 @@ exports.hashAndSign = function (key, msg, callback) {
exports.hashAndVerify = function (key, sig, msg, callback) {
setImmediate(() => {
callback(null, nacl.sign.detached.verify(msg, sig, key))
let result
try {
result = nacl.sign.detached.verify(msg, sig, key)
} catch (err) {
return callback(err)
}
callback(null, result)
})
}

View File

@@ -1,16 +1,23 @@
'use strict'
const protobuf = require('protocol-buffers')
const pbm = protobuf(require('./keys.proto'))
const keys = exports.keys = require('./keys')
const protobuf = require('protons')
const keysPBM = protobuf(require('./keys.proto'))
const jsrsasign = require('jsrsasign')
const KEYUTIL = jsrsasign.KEYUTIL
exports = module.exports
exports.pbm = pbm
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 = keys[keyType.toLowerCase()]
const key = supportedKeys[keyType.toLowerCase()]
return key !== undefined
}
@@ -19,7 +26,7 @@ exports.generateEphemeralKeyPair = require('./ephemeral-keys')
// Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits, cb) => {
let key = keys[type.toLowerCase()]
let key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
@@ -31,7 +38,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 = keys[type.toLowerCase()]
let key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
}
@@ -44,16 +51,17 @@ exports.generateKeyPairFromSeed = (type, seed, bits, cb) => {
// Converts a protobuf serialized public key into its
// representative object
exports.unmarshalPublicKey = (buf) => {
const decoded = pbm.PublicKey.decode(buf)
const decoded = keysPBM.PublicKey.decode(buf)
const data = decoded.Data
switch (decoded.Type) {
case pbm.KeyType.RSA:
return keys.rsa.unmarshalRsaPublicKey(decoded.Data)
case pbm.KeyType.Ed25519:
return keys.ed25519.unmarshalEd25519PublicKey(decoded.Data)
case pbm.KeyType.Secp256k1:
if (keys.secp256k1) {
return keys.secp256k1.unmarshalSecp256k1PublicKey(decoded.Data)
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')
}
@@ -75,16 +83,23 @@ exports.marshalPublicKey = (key, type) => {
// Converts a protobuf serialized private key into its
// representative object
exports.unmarshalPrivateKey = (buf, callback) => {
const decoded = pbm.PrivateKey.decode(buf)
let decoded
try {
decoded = keysPBM.PrivateKey.decode(buf)
} catch (err) {
return callback(err)
}
const data = decoded.Data
switch (decoded.Type) {
case pbm.KeyType.RSA:
return keys.rsa.unmarshalRsaPrivateKey(decoded.Data, callback)
case pbm.KeyType.Ed25519:
return keys.ed25519.unmarshalEd25519PrivateKey(decoded.Data, callback)
case pbm.KeyType.Secp256k1:
if (keys.secp256k1) {
return keys.secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, callback)
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'))
}
@@ -102,3 +117,17 @@ exports.marshalPrivateKey = (key, type) => {
return key.bytes
}
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()}'`)
}
} catch (err) {
callback(err)
}
}

View File

@@ -1,7 +1,6 @@
'use strict'
const whilst = require('async/whilst')
const Buffer = require('safe-buffer').Buffer
const hmac = require('../hmac')
const cipherMap = {

View File

@@ -1,7 +0,0 @@
'use strict'
module.exports = {
rsa: require('./rsa-class'),
ed25519: require('./ed25519-class'),
secp256k1: require('libp2p-crypto-secp256k1')
}

View File

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

View File

@@ -1,7 +1,6 @@
'use strict'
const nodeify = require('nodeify')
const Buffer = require('safe-buffer').Buffer
const nodeify = require('../nodeify')
const webcrypto = require('../webcrypto.js')()
@@ -18,11 +17,11 @@ exports.generateKey = function (bits, callback) {
true,
['sign', 'verify']
)
.then(exportKey)
.then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
.then(exportKey)
.then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
// Takes a jwk key
@@ -106,9 +105,7 @@ function derivePublicFromPrivate (jwKey) {
{
kty: jwKey.kty,
n: jwKey.n,
e: jwKey.e,
alg: jwKey.alg,
kid: jwKey.kid
e: jwKey.e
},
{
name: 'RSASSA-PKCS1-v1_5',

View File

@@ -1,10 +1,13 @@
'use strict'
const multihashing = require('multihashing-async')
const protobuf = require('protocol-buffers')
const protobuf = require('protons')
const bs58 = require('bs58')
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
const KEYUTIL = require('jsrsasign').KEYUTIL
const setImmediate = require('async/setImmediate')
class RsaPublicKey {
constructor (key) {
@@ -89,6 +92,60 @@ class RsaPrivateKey {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @param {function(Error, id)} callback
* @returns {undefined}
*/
id (callback) {
this.public.hash((err, hash) => {
if (err) {
return callback(err)
}
callback(null, bs58.encode(hash))
})
}
/**
* Exports the key into a password protected PEM format
*
* @param {string} [format] - Defaults to 'pkcs-8'.
* @param {string} password - The password to read the encrypted PEM
* @param {function(Error, KeyInfo)} callback
* @returns {undefined}
*/
export (format, password, callback) {
if (typeof password === 'function') {
callback = password
password = format
format = 'pkcs-8'
}
setImmediate(() => {
ensure(callback)
let err = null
let pem = null
try {
const key = KEYUTIL.getKey(this._key) // _key is a JWK (JSON Web Key)
if (format === 'pkcs-8') {
pem = KEYUTIL.getPEM(key, 'PKCS8PRV', password)
} else {
err = new Error(`Unknown export format '${format}'`)
}
} catch (e) {
err = e
}
callback(err, pem)
})
}
}
function unmarshalRsaPrivateKey (bytes, callback) {
@@ -108,6 +165,16 @@ function unmarshalRsaPublicKey (bytes) {
return new RsaPublicKey(jwk)
}
function fromJwk (jwk, callback) {
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
}
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
}
function generateKeyPair (bits, cb) {
crypto.generateKey(bits, (err, keys) => {
if (err) {
@@ -129,5 +196,6 @@ module.exports = {
RsaPrivateKey,
unmarshalRsaPublicKey,
unmarshalRsaPrivateKey,
generateKeyPair
generateKeyPair,
fromJwk
}

View File

@@ -9,30 +9,36 @@ const jwkToPem = require('pem-jwk').jwk2pem
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
const done = (err, res) => setImmediate(() => callback(err, res))
setImmediate(() => {
let result
try {
const key = keypair({ bits: bits })
result = {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
}
} catch (err) {
return callback(err)
}
let key
try {
key = keypair({ bits: bits })
} catch (err) {
return done(err)
}
done(null, {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
callback(null, result)
})
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
setImmediate(() => {
if (!key) {
return callback(new Error('Key is invalid'))
}
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
})
})
}
@@ -41,16 +47,33 @@ exports.getRandomValues = function (arr) {
}
exports.hashAndSign = function (key, msg, callback) {
const sign = crypto.createSign('RSA-SHA256')
setImmediate(() => {
let result
try {
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
const pem = jwkToPem(key)
result = sign.sign(pem)
} catch (err) {
return callback(new Error('Key or message is invalid!: ' + err.message))
}
sign.update(msg)
setImmediate(() => callback(null, sign.sign(jwkToPem(key))))
callback(null, result)
})
}
exports.hashAndVerify = function (key, sig, msg, callback) {
const verify = crypto.createVerify('RSA-SHA256')
setImmediate(() => {
let result
try {
const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
const pem = jwkToPem(key)
result = verify.verify(pem, sig)
} catch (err) {
return callback(new Error('Key or message is invalid!:' + err.message))
}
verify.update(msg)
setImmediate(() => callback(null, verify.verify(jwkToPem(key), sig)))
callback(null, result)
})
}

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

41
src/pbkdf2.js Normal file
View File

@@ -0,0 +1,41 @@
'use strict'
const crypto = require('jsrsasign').CryptoJS
/**
* Maps an IPFS hash name to its jsrsasign 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
}
/**
* Computes the Password-Based Key Derivation Function 2.
*
* @param {string} password
* @param {string} salt
* @param {number} iterations
* @param {number} keySize (in bytes)
* @param {string} hash - The hash name ('sha1', 'sha2-512, ...)
* @returns {string} - A new password
*/
function pbkdf2 (password, salt, iterations, keySize, hash) {
const opts = {
iterations: iterations,
keySize: keySize / 4, // convert bytes to words (32 bits)
hasher: hashName[hash]
}
if (!opts.hasher) {
throw new Error(`Hash '${hash}' is unknown or not supported`)
}
const words = crypto.PBKDF2(password, salt, opts)
return crypto.enc.Base64.stringify(words)
}
module.exports = pbkdf2

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

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

View File

@@ -1,7 +1,6 @@
'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
@@ -11,8 +10,8 @@ exports.toBase64 = function toBase64 (bn, len) {
return s
.replace(/(=*)$/, '') // Remove any trailing '='s
.replace(/\+/g, '-') // 62nd char of encoding
.replace(/\//g, '_') // 63rd char of encoding
.replace(/\+/g, '-') // 62nd char of encoding
.replace(/\//g, '_') // 63rd char of encoding
}
// Convert a base64 encoded string to a BN.js instance

View File

@@ -7,7 +7,6 @@ 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')

View File

@@ -9,7 +9,8 @@ chai.use(dirtyChai)
const crypto = require('../src')
const fixtures = require('./fixtures/go-key-rsa')
describe('libp2p-crypto', () => {
describe('libp2p-crypto', function () {
this.timeout(20 * 1000)
let key
before((done) => {
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
@@ -106,6 +107,32 @@ describe('libp2p-crypto', () => {
})
})
describe('pbkdf2', () => {
it('generates a derived password using sha1', () => {
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'sha1')
expect(p1).to.exist()
expect(p1).to.be.a('string')
})
it('generates a derived password using sha2-512', () => {
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'sha2-512')
expect(p1).to.exist()
expect(p1).to.be.a('string')
})
it('generates the same derived password with the same options', () => {
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 10, 512 / 8, 'sha1')
const p2 = crypto.pbkdf2('password', 'at least 16 character salt', 10, 512 / 8, 'sha1')
const p3 = crypto.pbkdf2('password', 'at least 16 character salt', 11, 512 / 8, 'sha1')
expect(p2).to.equal(p1)
expect(p3).to.not.equal(p2)
})
it('throws on invalid hash name', () => {
expect(() => crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'shaX-xxx')).to.throw()
})
})
describe('randomBytes', () => {
it('throws with no number passed', () => {
expect(() => {

View File

@@ -1,7 +1,5 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
module.exports = {
curve: 'P-256',
bob: {

View File

@@ -1,7 +1,5 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
module.exports = {
// These were generated in a gore (https://github.com/motemen/gore) repl session:
//

View File

@@ -1,7 +1,5 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
module.exports = {
private: {
hash: Buffer.from([

View File

@@ -1,7 +1,5 @@
'use strict'
const Buffer = require('safe-buffer').Buffer
module.exports = [{
cipher: 'AES-256',
hash: 'SHA256',

View File

@@ -1,9 +1,6 @@
'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'),

View File

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

View File

@@ -2,7 +2,6 @@
/* eslint-env mocha */
'use strict'
const Buffer = require('safe-buffer').Buffer
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect

View File

@@ -5,13 +5,15 @@ 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.keys.ed25519
const ed25519 = crypto.keys.supportedKeys.ed25519
const fixtures = require('../fixtures/go-key-ed25519')
describe('ed25519', () => {
const testGarbage = require('../helpers/test-garbage-error-handling')
describe('ed25519', function () {
this.timeout(20 * 1000)
let key
before((done) => {
crypto.keys.generateKeyPair('Ed25519', 512, (err, _key) => {
@@ -115,6 +117,15 @@ describe('ed25519', () => {
})
})
it('key id', (done) => {
key.id((err, id) => {
expect(err).to.not.exist()
expect(id).to.exist()
expect(id).to.be.a('string')
done()
})
})
describe('key equals', () => {
it('equals itself', () => {
expect(
@@ -177,6 +188,12 @@ describe('ed25519', () => {
})
})
describe('returns error via cb instead of crashing', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
testGarbage.doTests('key.verify', key.verify.bind(key), 2)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
})
describe('go interop', () => {
let privateKey

View File

@@ -1,3 +1,4 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
@@ -5,13 +6,16 @@ const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const Buffer = require('safe-buffer').Buffer
chai.use(require('chai-string'))
const crypto = require('../../src')
const rsa = crypto.keys.keys.rsa
const rsa = crypto.keys.supportedKeys.rsa
const fixtures = require('../fixtures/go-key-rsa')
describe('RSA', () => {
const testGarbage = require('../helpers/test-garbage-error-handling')
describe('RSA', function () {
this.timeout(20 * 1000)
let key
before((done) => {
@@ -76,6 +80,15 @@ describe('RSA', () => {
})
})
it('key id', (done) => {
key.id((err, id) => {
expect(err).to.not.exist()
expect(id).to.exist()
expect(id).to.be.a('string')
done()
})
})
describe('key equals', () => {
it('equals itself', () => {
expect(key.equals(key)).to.eql(true)
@@ -132,6 +145,50 @@ describe('RSA', () => {
})
})
describe('export and import', () => {
it('password protected PKCS #8', (done) => {
key.export('pkcs-8', 'my secret', (err, pem) => {
expect(err).to.not.exist()
expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----')
crypto.keys.import(pem, 'my secret', (err, clone) => {
expect(err).to.not.exist()
expect(clone).to.exist()
expect(key.equals(clone)).to.eql(true)
done()
})
})
})
it('defaults to PKCS #8', (done) => {
key.export('another secret', (err, pem) => {
expect(err).to.not.exist()
expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----')
crypto.keys.import(pem, 'another secret', (err, clone) => {
expect(err).to.not.exist()
expect(clone).to.exist()
expect(key.equals(clone)).to.eql(true)
done()
})
})
})
it('needs correct password', (done) => {
key.export('another secret', (err, pem) => {
expect(err).to.not.exist()
crypto.keys.import(pem, 'not the secret', (err, clone) => {
expect(err).to.exist()
done()
})
})
})
})
describe('returns error via cb instead of crashing', () => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
testGarbage.doTests('key.verify', key.verify.bind(key), 2, true)
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys))
})
describe('go interop', () => {
it('verifies with data from go', (done) => {
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
@@ -144,4 +201,170 @@ describe('RSA', () => {
})
})
})
describe('openssl interop', () => {
it('can read a private key', (done) => {
/*
* Generated with
* openssl genpkey -algorithm RSA
* -pkeyopt rsa_keygen_bits:3072
* -pkeyopt rsa_keygen_pubexp:65537
*/
const pem = `-----BEGIN PRIVATE KEY-----
MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK
0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO
v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb
ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75
Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR
xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV
CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ
+Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0
HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA
ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo
NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo
qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5
0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv
4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT
cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL
pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW
YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB
AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c
V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB
VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v
obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl
oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL
nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr
olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU
NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz
KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW
wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4
uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT
FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY
bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI
/hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60
dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a
w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev
blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2
rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD
vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h
gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn
4pMwXeXP+LO8NIfRXV8mgrm86g==
-----END PRIVATE KEY-----
`
crypto.keys.import(pem, '', (err, key) => {
expect(err).to.not.exist()
expect(key).to.exist()
key.id((err, id) => {
expect(err).to.not.exist()
expect(id).to.equal('QmfWu2Xp8DZzCkZZzoPB9rcrq4R4RZid6AWE6kmrUAzuHy')
done()
})
})
})
// AssertionError: expected 'this only supports pkcs5PBES2' to not exist
it.skip('can read a private encrypted key (v1)', (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 -passout pass:mypassword
*/
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICoTAbBgkqhkiG9w0BBQMwDgQI2563Jugj/KkCAggABIICgPxHkKtUUE8EWevq
eX9nTjqpbsv0QoXQMhegfxDELJLU8tj6V0bWNt7QDdfQ1n6FRgnNvNGick6gyqHH
yH9qC2oXwkDFP7OrHp2NEZd7DHQLLc+L4KJ/0dzsiZ1U9no7XzQMUay9Bc918ADE
pN2/EqigWkaG4gNjkAeKWr6+BNRevDXlSvls7YDboNcTiACi5zJkthivB9g3vT1m
gPdN6Gf/mmqtBTDHeqj5QsmXYqeCyo5b26JgYsziABVZDHph4ekPUsTvudRpE9Ex
baXwdYEAZxVpSbTvQ3A5qysjSZeM9ttfRTSSwL391q7dViz4+aujpk0Vj7piH+1B
CkfO8/XudRdRlnOe+KjMidktKCsMGCIOW92IlfMvIQ/Zn1GTYj9bRXONFNJ2WPND
UmCKnL7cmworwg/weRorrGKBWIGspU+tDASOPSvIGKo6Hoxm4CN1TpDRY7DAGlgm
Y3TEbMYfpXyzkPjvAhJDt03D3J9PrTO6uM5d7YUaaTmJ2TQFQVF2Lc3Uz8lDJLs0
ZYtfQ/4H+YY2RrX7ua7t6ArUcYXZtv0J4lRYWjwV8fGPUVc0d8xLJU0Yjf4BD7K8
rsavHo9b5YvBUX7SgUyxAEembEOe3SjQ+gPu2U5wovcjUuC9eItEEsXGrx30BQ0E
8BtK2+hp0eMkW5/BYckJkH+Yl8ypbzRGRRIZzLgeI4JveSx/mNhewfgTr+ORPThZ
mBdkD5r+ixWF174naw53L8U9wF8kiK7pIE1N9TR4USEeovLwX6Ni/2MMDZedOfof
2f77eUdLsK19/5/lcgAAYaXauXWhy2d2r3SayFrC9woy0lh2VLKRMBjcx1oWb7dp
0uxzo5Y=
-----END ENCRYPTED PRIVATE KEY-----
`
crypto.keys.import(pem, 'mypassword', (err, key) => {
expect(err).to.not.exist()
expect(key).to.exist()
done()
})
})
// AssertionError: expected 'this only supports TripleDES' to not exist
it.skip('can read a private encrypted key (v2 aes-256-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-256-cbc -passout pass:mypassword
*/
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIhuL894loRucCAggA
MB0GCWCGSAFlAwQBKgQQEoEtsjW3iC9/u0uGvkxX7wSCAoAsX3l6JoR2OGbT8CkY
YT3RQFqquOgItYOHw6E3tir2YrmxEAo99nxoL8pdto37KSC32eAGnfv5R1zmHHSx
0M3/y2AWiCBTX95EEzdtGC1hK3PBa/qpp/xEmcrsjYN6NXxMAkhC0hMP/HdvqMAg
ee7upvaYJsJcl8QLFNayAWr8b8cZA/RBhGEIRl59Eyj6nNtxDt3bCrfe06o1CPCV
50/fRZEwFOi/C6GYvPN6MrPZO3ALBWgopLT2yQqycTKtfxYWIdOsMBkAjKf2D6Pk
u2mqBsaP4b71jIIeT4euSJLsoJV+O39s8YHXtW8GtOqp7V5kIlnm90lZ9wzeLTZ7
HJsD/jEdYto5J3YWm2wwEDccraffJSm7UDtJBvQdIx832kxeFCcGQjW38Zl1qqkg
iTH1PLTypxj2ZuviS2EkXVFb/kVU6leWwOt6fqWFC58UvJKeCk/6veazz3PDnTWM
92ClUqFd+CZn9VT4CIaJaAc6v5NLpPp+T9sRX9AtequPm7FyTeevY9bElfyk9gW9
JDKgKxs6DGWDa16RL5vzwtU+G3o6w6IU+mEwa6/c+hN+pRFs/KBNLLSP9OHBx7BJ
X/32Ft+VFhJaK+lQ+f+hve7od/bgKnz4c/Vtp7Dh51DgWgCpBgb8p0vqu02vTnxD
BXtDv3h75l5PhvdWfVIzpMWRYFvPR+vJi066FjAz2sjYc0NMLSYtZWyWoIInjhoX
Dp5CQujCtw/ZSSlwde1DKEWAW4SeDZAOQNvuz0rU3eosNUJxEmh3aSrcrRtDpw+Y
mBUuWAZMpz7njBi7h+JDfmSW/GAaMwrVFC2gef5375R0TejAh+COAjItyoeYEvv8
DQd8
-----END ENCRYPTED PRIVATE KEY-----
`
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
* openssl genpkey -algorithm RSA
* -pkeyopt rsa_keygen_bits:1024
* -pkeyopt rsa_keygen_pubexp:65537
* -out foo.pem
* openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword
*/
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA
MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w
2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi
wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg
SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2
dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm
kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3
Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh
hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy
qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC
TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW
3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w
6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV
NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6
DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG
-----END ENCRYPTED PRIVATE KEY-----
`
crypto.keys.import(pem, 'mypassword', (err, key) => {
expect(err).to.not.exist()
expect(key).to.exist()
done()
})
})
})
})

View File

@@ -32,7 +32,7 @@ const mockSecp256k1Module = {
}
describe('without libp2p-crypto-secp256k1 module present', () => {
crypto.keys.keys['secp256k1'] = undefined
crypto.keys.supportedKeys.secp256k1 = undefined
it('fails to generate a secp256k1 key', (done) => {
crypto.keys.generateKeyPair('secp256k1', 256, (err, key) => {
@@ -61,7 +61,7 @@ describe('with libp2p-crypto-secp256k1 module present', () => {
let key
before((done) => {
crypto.keys.keys['secp256k1'] = mockSecp256k1Module
crypto.keys.supportedKeys.secp256k1 = mockSecp256k1Module
crypto.keys.generateKeyPair('secp256k1', 256, (err, _key) => {
if (err) return done(err)
key = _key
@@ -70,7 +70,7 @@ describe('with libp2p-crypto-secp256k1 module present', () => {
})
after((done) => {
delete crypto.keys['secp256k1']
delete crypto.keys.secp256k1
done()
})