mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-03-15 19:50:58 +00:00
finish rsa implementation
This commit is contained in:
parent
37edb7d0e4
commit
f3a22ea5ff
@ -17,3 +17,10 @@ needed for libp2p. This is based on this [go implementation](https://github.com/
|
||||
|
||||
|
||||
## API
|
||||
|
||||
|
||||
### `generateKeyPair(type, bits, cb)`
|
||||
|
||||
- `type: String`, only `'RSA'` is currently supported
|
||||
- `bits: Number`
|
||||
- `cb: Function`, with the signature `function (err, privateKey)`
|
||||
|
17
package.json
17
package.json
@ -24,6 +24,11 @@
|
||||
],
|
||||
"author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"multihashing": "^0.2.1",
|
||||
"node-forge": "^0.6.39",
|
||||
"protocol-buffers": "^3.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aegir": "^3.0.4",
|
||||
"chai": "^3.5.0",
|
||||
@ -44,9 +49,13 @@
|
||||
"url": "https://github.com/ipfs/js-libp2p-crypto/issues"
|
||||
},
|
||||
"homepage": "https://github.com/ipfs/js-libp2p-crypto",
|
||||
"dependencies": {
|
||||
"multihashing": "^0.2.1",
|
||||
"node-forge": "^0.6.39",
|
||||
"protocol-buffers": "^3.1.6"
|
||||
"aegir": {
|
||||
"webpack": {
|
||||
"resolve": {
|
||||
"alias": {
|
||||
"node-forge": "../../vendor/forge.bundle.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
src/index.js
11
src/index.js
@ -1,17 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
const keyGenerators = require('./keys')
|
||||
|
||||
exports.utils = require('./utils')
|
||||
const keys = exports.keys = require('./keys')
|
||||
|
||||
// Generates a keypair of the given type and bitsize
|
||||
exports.generateKeyPair = (type, bits) => {
|
||||
let generator = keyGenerators[type.toLowerCase()]
|
||||
if (!generator) {
|
||||
exports.generateKeyPair = (type, bits, cb) => {
|
||||
let key = keys[type.toLowerCase()]
|
||||
if (!key) {
|
||||
throw new Error('invalid or unsupported key type')
|
||||
}
|
||||
|
||||
return generator(bits)
|
||||
key.generateKeyPair(bits, cb)
|
||||
}
|
||||
|
||||
// Generates an ephemeral public key and returns a function that will compute
|
||||
|
@ -25,13 +25,13 @@ class RsaPublicKey {
|
||||
}
|
||||
|
||||
marshal () {
|
||||
return forge.asn1.toDer(pki.privateKeyToAsn1(this._key)).bytes()
|
||||
return forge.asn1.toDer(pki.publicKeyToAsn1(this._key)).bytes()
|
||||
}
|
||||
|
||||
get bytes () {
|
||||
return pbm.PublicKey.encode({
|
||||
Type: pbm.KeyType.RSA,
|
||||
Data: this.marhal()
|
||||
Data: this.marshal()
|
||||
})
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ class RsaPublicKey {
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes === key.bytes
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
hash () {
|
||||
@ -85,7 +85,7 @@ class RsaPrivateKey {
|
||||
}
|
||||
|
||||
equals (key) {
|
||||
return this.bytes === key.bytes
|
||||
return this.bytes.equals(key.bytes)
|
||||
}
|
||||
|
||||
hash () {
|
||||
@ -105,10 +105,21 @@ function unmarshalRsaPublicKey (bytes) {
|
||||
return new RsaPublicKey(key)
|
||||
}
|
||||
|
||||
module.exports = function generateRSAKey (bits, cb) {
|
||||
rsa.generateKeyPair({bits}, (err, keypair) => {
|
||||
function generateKeyPair (bits, cb) {
|
||||
rsa.generateKeyPair({
|
||||
bits,
|
||||
workerScript: utils.workerScript
|
||||
}, (err, p) => {
|
||||
if (err) return cb(err)
|
||||
|
||||
cb(null, new RSAKey(keypair.publicKey, keypair.privateKey))
|
||||
cb(null, new RsaPrivateKey(p.privateKey, p.publicKey))
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RsaPublicKey,
|
||||
RsaPrivateKey,
|
||||
unmarshalRsaPublicKey,
|
||||
unmarshalRsaPrivateKey,
|
||||
generateKeyPair
|
||||
}
|
||||
|
39
src/utils.js
39
src/utils.js
@ -1,13 +1,40 @@
|
||||
'use strict'
|
||||
|
||||
const multihashing = require('multihashing')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
// Check the equality of two keys
|
||||
exports.keyEqual = (k1, k2) => {
|
||||
return k1.buffer.equals(k2.buffer)
|
||||
}
|
||||
const URL = global.window && (window.URL || window.webkitURL)
|
||||
|
||||
// Hashes a key
|
||||
exports.keyHash = (key) => {
|
||||
return multihashing(key.buffer, 'sha2-256')
|
||||
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 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())
|
||||
|
@ -4,16 +4,115 @@
|
||||
const expect = require('chai').expect
|
||||
|
||||
const crypto = require('../src')
|
||||
const rsa = crypto.keys.rsa
|
||||
|
||||
describe('libp2p-crypto', () => {
|
||||
describe('generateKeyPair', () => {
|
||||
describe('RSA', () => {
|
||||
it('generates a valid key', () => {
|
||||
const key = crypto.generateKeyPair('RSA', 2048)
|
||||
let key
|
||||
before((done) => {
|
||||
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
|
||||
if (err) return done(err)
|
||||
key = _key
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
expect(key).to.have.property('publicKey')
|
||||
expect(key).to.have.property('privateKey')
|
||||
expect(key).to.have.property('buffer')
|
||||
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', (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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
29552
vendor/forge.bundle.js
vendored
Normal file
29552
vendor/forge.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1486
vendor/prime.worker.js
vendored
Normal file
1486
vendor/prime.worker.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user