Skip to content
This repository was archived by the owner on Jul 21, 2023. It is now read-only.

feat(rsa): always use the fastest method available for rsa keygeneration #10

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .aegir.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ module.exports = {
alias: {
'node-forge': path.resolve(__dirname, 'vendor/forge.bundle.js')
}
},
externals: {
ursa: '{}'
}
}
}
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ needed for libp2p. This is based on this [go implementation](https://github.com/
- [Usage](#usage)
- [Example](#example)
- [API](#api)
- [`generateKeyPair(type, bits)`](#generatekeypairtype-bits)
- [`generateKeyPair(type, bits, cb)`](#generatekeypairtype-bits-cb)
- [`generateEphemeralKeyPair(curve)`](#generateephemeralkeypaircurve)
- [`keyStretcher(cipherType, hashType, secret)`](#keystretcherciphertype-hashtype-secret)
- [`marshalPublicKey(key[, type])`](#marshalpublickeykey-type)
Expand All @@ -44,15 +44,17 @@ npm install --save libp2p-crypto
```js
const crypto = require('libp2p-crypto')

var keyPair = crypto.generateKeyPair('RSA', 2048)
crypto.generateKeyPair('RSA', 2048, (err, key) => {
})
```

## API

### `generateKeyPair(type, bits)`
### `generateKeyPair(type, bits, cb)`

- `type: String`, only `'RSA'` is currently supported
- `bits: Number`
- `cb: Function`

Generates a keypair of the given type and bitsize.

Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "libp2p-crypto",
"version": "0.6.1",
"description": "Crypto primitives for libp2p",
"main": "lib/index.js",
"main": "src/index.js",
Copy link
Member Author

@dignifiedquire dignifiedquire Sep 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Todo: revert before merge

"jsnext:main": "src/index.js",
"scripts": {
"lint": "aegir-lint",
Expand Down Expand Up @@ -55,5 +55,8 @@
"Friedel Ziegelmayer <[email protected]>",
"Richard Littauer <[email protected]>",
"greenkeeperio-bot <[email protected]>"
]
}
],
"optionalDependencies": {
"ursa": "^0.9.4"
}
}
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ exports.keyStretcher = require('./key-stretcher')
exports.generateEphemeralKeyPair = require('./ephemeral-keys')

// Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits) => {
exports.generateKeyPair = (type, bits, cb) => {
let key = keys[type.toLowerCase()]
if (!key) {
throw new Error('invalid or unsupported key type')
}

return key.generateKeyPair(bits)
return key.generateKeyPair(bits, cb)
}

// Converts a protobuf serialized public key into its
Expand Down
36 changes: 33 additions & 3 deletions src/keys/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,39 @@ function unmarshalRsaPublicKey (bytes) {
return new RsaPublicKey(key)
}

function generateKeyPair (bits) {
const p = rsa.generateKeyPair({bits})
return new RsaPrivateKey(p.privateKey, p.publicKey)
function fastKeys (bits, cb) {
if (typeof window === 'undefined') {
let ursa
try {
ursa = require('ursa')
} catch (err) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should at least show a warning if something goes wrong here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? This is simply the check if the optional dependency is available to be used

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, did not know is what an optional dependency and my spidey senses goes off when I see a empty catch in a try/catch block.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As they should :)

}

if (ursa && ursa.generatePrivateKey) {
const key = ursa.generatePrivateKey(bits, 65537)
cb(null, {
privateKey: pki.privateKeyFromPem(key.toPrivatePem().toString()),
publicKey: pki.publicKeyFromPem(key.toPublicPem().toString())
})
return
}
}

rsa.generateKeyPair({
bits,
workers: -1,
workerScript: utils.workerScript
}, cb)
}

function generateKeyPair (bits, cb) {
fastKeys(bits, (err, p) => {
if (err) {
return cb(err)
}

cb(null, new RsaPrivateKey(p.privateKey, p.publicKey))
})
}

module.exports = {
Expand Down
30 changes: 30 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
'use strict'

const fs = require('fs')
const path = require('path')
const multihashing = require('multihashing')

// Hashes a key
exports.keyHash = (bytes) => {
return multihashing(bytes, 'sha2-256')
}

const toBlob = (content) => {
try {
let blob
try {
// BlobBuilder = Deprecated, but widely implemented
const BlobBuilder = global.window &&
(window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder)

blob = new BlobBuilder()
blob.append(content)
blob = blob.getBlob()
} catch (e) {
// The proposed API
blob = new window.Blob([content])
}
return window.URL.createObjectURL(blob)
} catch (e) {
return 'data:application/javascript,' + encodeURIComponent(content)
}
}

const rawScript = fs.readFileSync(path.join(__dirname, '../vendor/prime.worker.js'))

exports.workerScript = toBlob(rawScript.toString())
8 changes: 6 additions & 2 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ const fixtures = require('./fixtures/go-key-rsa')

describe('libp2p-crypto', () => {
let key
before(() => {
key = crypto.generateKeyPair('RSA', 2048)
before((done) => {
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) return done(err)
key = _key
done()
})
})

it('marshalPublicKey and unmarshalPublicKey', () => {
Expand Down
63 changes: 35 additions & 28 deletions test/rsa.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ const rsa = crypto.keys.rsa

describe('RSA', () => {
let key
before(() => {
key = crypto.generateKeyPair('RSA', 2048)
before((done) => {
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) return done(err)
key = _key
done()
})
})

it('generates a valid key', () => {
Expand Down Expand Up @@ -76,32 +80,35 @@ describe('RSA', () => {
)
})

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('not equals other key', (done) => {
crypto.generateKeyPair('RSA', 2048, (err, key2) => {
if (err) return done(err)

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

Expand Down
Loading