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
|
## 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>",
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/index.js
11
src/index.js
@ -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
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
39
src/utils.js
39
src/utils.js
@ -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())
|
||||||
|
@ -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
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