finish rsa implementation

This commit is contained in:
dignifiedquire 2016-05-19 20:18:31 +02:00
parent 37edb7d0e4
commit f3a22ea5ff
8 changed files with 31218 additions and 28 deletions

View File

@ -17,3 +17,10 @@ needed for libp2p. This is based on this [go implementation](https://github.com/
## API ## API
### `generateKeyPair(type, bits, cb)`
- `type: String`, only `'RSA'` is currently supported
- `bits: Number`
- `cb: Function`, with the signature `function (err, privateKey)`

View File

@ -24,6 +24,11 @@
], ],
"author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>", "author": "Friedel Ziegelmayer <dignifiedqurie@gmail.com>",
"license": "MIT", "license": "MIT",
"dependencies": {
"multihashing": "^0.2.1",
"node-forge": "^0.6.39",
"protocol-buffers": "^3.1.6"
},
"devDependencies": { "devDependencies": {
"aegir": "^3.0.4", "aegir": "^3.0.4",
"chai": "^3.5.0", "chai": "^3.5.0",
@ -44,9 +49,13 @@
"url": "https://github.com/ipfs/js-libp2p-crypto/issues" "url": "https://github.com/ipfs/js-libp2p-crypto/issues"
}, },
"homepage": "https://github.com/ipfs/js-libp2p-crypto", "homepage": "https://github.com/ipfs/js-libp2p-crypto",
"dependencies": { "aegir": {
"multihashing": "^0.2.1", "webpack": {
"node-forge": "^0.6.39", "resolve": {
"protocol-buffers": "^3.1.6" "alias": {
"node-forge": "../../vendor/forge.bundle.js"
}
}
}
} }
} }

View File

@ -1,17 +1,16 @@
'use strict' 'use strict'
const keyGenerators = require('./keys')
exports.utils = require('./utils') exports.utils = require('./utils')
const keys = exports.keys = require('./keys')
// Generates a keypair of the given type and bitsize // Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits) => { exports.generateKeyPair = (type, bits, cb) => {
let generator = keyGenerators[type.toLowerCase()] let key = keys[type.toLowerCase()]
if (!generator) { if (!key) {
throw new Error('invalid or unsupported key type') 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 // Generates an ephemeral public key and returns a function that will compute

View File

@ -25,13 +25,13 @@ class RsaPublicKey {
} }
marshal () { marshal () {
return forge.asn1.toDer(pki.privateKeyToAsn1(this._key)).bytes() return forge.asn1.toDer(pki.publicKeyToAsn1(this._key)).bytes()
} }
get bytes () { get bytes () {
return pbm.PublicKey.encode({ return pbm.PublicKey.encode({
Type: pbm.KeyType.RSA, Type: pbm.KeyType.RSA,
Data: this.marhal() Data: this.marshal()
}) })
} }
@ -40,7 +40,7 @@ class RsaPublicKey {
} }
equals (key) { equals (key) {
return this.bytes === key.bytes return this.bytes.equals(key.bytes)
} }
hash () { hash () {
@ -85,7 +85,7 @@ class RsaPrivateKey {
} }
equals (key) { equals (key) {
return this.bytes === key.bytes return this.bytes.equals(key.bytes)
} }
hash () { hash () {
@ -105,10 +105,21 @@ function unmarshalRsaPublicKey (bytes) {
return new RsaPublicKey(key) return new RsaPublicKey(key)
} }
module.exports = function generateRSAKey (bits, cb) { function generateKeyPair (bits, cb) {
rsa.generateKeyPair({bits}, (err, keypair) => { rsa.generateKeyPair({
bits,
workerScript: utils.workerScript
}, (err, p) => {
if (err) return cb(err) 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
}

View File

@ -1,13 +1,40 @@
'use strict' 'use strict'
const multihashing = require('multihashing') const multihashing = require('multihashing')
const path = require('path')
const fs = require('fs')
// Check the equality of two keys const URL = global.window && (window.URL || window.webkitURL)
exports.keyEqual = (k1, k2) => {
return k1.buffer.equals(k2.buffer)
}
// Hashes a key // Hashes a key
exports.keyHash = (key) => { exports.keyHash = (bytes) => {
return multihashing(key.buffer, 'sha2-256') 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())

View File

@ -4,16 +4,115 @@
const expect = require('chai').expect const expect = require('chai').expect
const crypto = require('../src') const crypto = require('../src')
const rsa = crypto.keys.rsa
describe('libp2p-crypto', () => { describe('libp2p-crypto', () => {
describe('generateKeyPair', () => { describe('generateKeyPair', () => {
describe('RSA', () => { describe('RSA', () => {
it('generates a valid key', () => { let key
const key = crypto.generateKeyPair('RSA', 2048) before((done) => {
crypto.generateKeyPair('RSA', 2048, (err, _key) => {
if (err) return done(err)
key = _key
done()
})
})
expect(key).to.have.property('publicKey') it('generates a valid key', () => {
expect(key).to.have.property('privateKey') expect(
expect(key).to.have.property('buffer') 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

File diff suppressed because it is too large Load Diff

1486
vendor/prime.worker.js vendored Normal file

File diff suppressed because it is too large Load Diff