keys now generated and derived match with go client

This commit is contained in:
nginnever 2016-02-02 15:50:45 -08:00
parent 5cb511c646
commit 6ce01ab434
5 changed files with 138 additions and 23 deletions

View File

@ -6,7 +6,10 @@ peer-id JavaScript implementation
# Description
A IPFS Peer Id is based on a sha256 has of the peer public key, using [multihash](https://github.com/jbenet/multihash)
A IPFS Peer Id is based on a sha256 hash of the peer public key, using [multihash](https://github.com/jbenet/multihash)
The public key is currently a base64 encoded string of a protobuf of an RSA DER buffer. This uses a node buffer to pass the base64 encoded public key protobuf to the multihash for ID generation.
# Usage

View File

@ -40,8 +40,8 @@
},
"dependencies": {
"bs58": "^3.0.0",
"keypair": "^1.0.0",
"multihashing": "^0.2.0",
"node-forge": "^0.6.38"
"node-forge": "^0.6.38",
"protocol-buffers": "^3.1.4"
}
}

15
src/crypto.proto Normal file
View File

@ -0,0 +1,15 @@
package crypto.pb;
enum KeyType {
RSA = 0;
}
message PublicKey {
required KeyType Type = 1;
required bytes Data = 2;
}
message PrivateKey {
required KeyType Type = 1;
required bytes Data = 2;
}

View File

@ -2,10 +2,14 @@
* Id is an object representation of a peer Id. a peer Id is a multihash
*/
var fs = require('fs')
var multihashing = require('multihashing')
var base58 = require('bs58')
var keypair = require('keypair')
var forge = require('node-forge')
var protobuf = require('protocol-buffers')
//protobuf read from file
var messages = protobuf(fs.readFileSync(__dirname+'/crypto.proto'))
exports = module.exports = Id
@ -26,7 +30,7 @@ function Id (id, privKey, pubKey) {
self.toPrint = function () {
return {
id: self.toHexString(),
id: self.toB58String(),
privKey: privKey.toString('hex'),
pubKey: pubKey.toString('hex')
}
@ -47,18 +51,78 @@ function Id (id, privKey, pubKey) {
}
}
function fix (str) {
return str.replace(/\r/g, '') + '\n'
//unwrap the private key protobuf stream
function unmarshal (key) {
var dpb = messages.PrivateKey.decode(key)
return dpb
}
//create a public key protobuf to be base64 string stored in config
function marshal (data, type) {
if(type == 'Public'){
var epb = messages.PublicKey.encode({
Type: 0,
Data: data
})
}
if(type == 'Private'){
var epb = messages.PrivateKey.encode({
Type: 0,
Data: data
})
}
return epb
}
// generation
exports.create = function () {
var pair = keypair()
//generate keys
var pair = forge.rsa.generateKeyPair({bits:2048, e: 0x10001})
var mhId = multihashing(pair.public, 'sha2-256')
//Create Public Key
//return the RSA public key to asn1 object and DER encode
var asnPub = forge.pki.publicKeyToAsn1(pair.publicKey)
return new Id(mhId, pair.private, pair.public)
//create der buffer of public key asn.1 object
var derPub = forge.asn1.toDer(asnPub)
//create forge buffer of der public key buffer
var fDerBuf = forge.util.createBuffer(derPub.data, 'binary')
//convert forge buffer to node buffer public key
var nDerBuf = new Buffer(fDerBuf.getBytes(), 'binary')
//protobuf the new DER bytes to the PublicKey Data: field
var marPubKey = marshal(nDerBuf, 'Public')
//encode the protobuf public key to base64 string
var pubKeyb64 = marPubKey.toString('base64')
//create Private Key
//return the RSA private key to asn1 object and DER encode
var asnPriv = forge.pki.privateKeyToAsn1(pair.privateKey)
//create der buffer of private key asn.1 object
var derPriv = forge.asn1.toDer(asnPriv)
//create forge buffer of der private key buffer
var fDerBufPriv = forge.util.createBuffer(derPriv.data, 'binary')
//convert forge buffer to node buffer private key
var nDerBufPriv = new Buffer(fDerBufPriv.getBytes(), 'binary')
//protobuf the new DER bytes to the PrivateKey Data: field
var marPrivKey = marshal(nDerBufPriv, 'Private')
//encode the protobuf private key to base64 string
var privKeyb64 = marPrivKey.toString('base64')
var mhId = multihashing(marPubKey, 'sha2-256')
return new Id(mhId, privKeyb64, pubKeyb64)
}
exports.createFromHexString = function (str) {
@ -74,17 +138,49 @@ exports.createFromB58String = function (str) {
}
exports.createFromPubKey = function (pubKey) {
var buf = new Buffer(pubKey, 'base64')
var mhId = multihashing(pubKey, 'sha2-256')
return new Id(mhId, null, pubKey)
}
exports.createFromPrivKey = function (privKey) {
var privateKey = forge.pki.privateKeyFromPem(privKey)
var publicKey = {
n: privateKey.n,
e: privateKey.e
}
var pubKey = fix(forge.pki.publicKeyToRSAPublicKeyPem(publicKey, 72))
var mhId = multihashing(pubKey, 'sha2-256')
return new Id(mhId, privKey, pubKey)
//create a buffer from the base64 encoded string
var buf = new Buffer(privKey, 'base64')
//get the private key data from the protobuf
var mpk = unmarshal(buf)
//create a forge buffer
var fbuf = forge.util.createBuffer(mpk.Data.toString('binary'))
//create an asn1 object from the private key bytes saved in the protobuf Data: field
var asnPriv = forge.asn1.fromDer(fbuf)
//get the RSA privatekey data from the asn1 object
var privateKey = forge.pki.privateKeyFromAsn1(asnPriv)
//set the RSA public key to the modulus and exponent of the private key
var publicKey = forge.pki.rsa.setPublicKey(privateKey.n, privateKey.e)
//return the RSA public to asn1 object and DER encode
var asnPub = forge.pki.publicKeyToAsn1(publicKey)
//create der buffer of public key asn.1 object
var derPub = forge.asn1.toDer(asnPub)
//create forge buffer of der buffer
var fDerBuf = forge.util.createBuffer(derPub.data, 'binary')
//convert forge buffer to node buffer
var nDerBuf = new Buffer(fDerBuf.getBytes(), 'binary')
//protobuf the new DER bytes to the PublicKey Data: field
var marPubKey = marshal(nDerBuf, 'Public')
//encode the protobuf public key to base64 string
var pubKeyb64 = marPubKey.toString('base64')
var mhId = multihashing(marPubKey, 'sha2-256')
return new Id(mhId, privKey, pubKeyb64)
}

View File

@ -3,8 +3,8 @@ var PeerId = require('../src')
var testId = {
id: '1220151ab1658d8294ab34b71d5582cfe20d06414212f440a69366f1bc31deb5c72d',
privKey: '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAgPEiGHOwFEUdo95/DaALH69umbFI4xD3Jmla0hiHbkcW535arBfFd8nJ\ns5VPt49sgdSgn1ZmiqmHLgMwMz6mKplu4GsmWj5mjdyxiNl5z6R2rF+ZziuiwRTeHVX/8zR8\nM7Cbh0QXmzpoq6LcNOFHbg495zsbmT9QAtjVsS1KyF5324mxbTZtjaD6hxJkAL8aVi0ikvhA\nL4HuZ1m3brjSSZ0+epFCFL7UIoJlFfOvap2sAyxdOrSvY2PXKTE00s51YTin5+CrvofRLCJP\nROls1oFkhXIDGfuTGTxMxe3hSUlNj0LjQi6RXPGat/5XH0nCuFTODmyhrnnnx51OdgT9vwID\nAQABAoIBAQAIAnKSwET0zWJM9po/12w5eKVPKMMVT816dlrs6Bcpk4LpuGCbhhJ/IWrFHAZK\nqb8cxX+AxlYyUNuT0SDiXgbmaIeJqz5DptKqB0aD8LZvXpD8nieote8zPT+a5Oe0TNNWRqcy\nnNk2jEdKOiChrEjKnlncDkDloRgwRRXpHp4hmh3XrZwygAekxC+LFhO5YS4fuc5tQAzGyl/O\nGKnEmOtRqz4bYQRTrrfhwtAWdMOC90AEtoIPapLnJPBUujHNn7KLktdrmlPSqxFilIIe3jJH\nH0oG9Nr9ueSNat54NQZr2BBrXliFqXu/SomiAfN0jmouB+8lzNYSoUK25JmbJQExAoGBANLE\nLqJS1DpLa3Mg/GMCeCbjWG6qwpLjJttFAG2F4Yst3elwr7EiSR4aEARFikFJXS2XX4Rf16FM\njI582Cfq3QuksJ3FHMXWv6qu+avROSYPTFrKkzLSD9qsALX5YlZRv/skwzpLeE7Vjy6g1y6E\ne7AwENVdJabWdRhlqKadCe/3AoGBAJydZUEGn7EKAG98XuXsrPrP1yVIdG7tdGEktXwjJ2Wi\nCCptWwNqH/cGU/Oxm60oDvE/z7DtsFMXKlLRisIV8UbRotQXNeEwe33bTXHAAnTaGXxJ8DxX\nddvPjnoeg7SqyaKxAZW4hP8BfKZJXEQtxcnPgXXpLpbEMH4giWhJwX55AoGBAKqqiUiP4aJC\nqANV1okl2r1Cor0aMOxYW4J6YVpOatAUl/kLcnjw1lw1pnqPBODQ006zoHjEUwsdvUMz/KR2\nHf/rn8hhcGcS+ajwfuOOS8Rx5tYt6vvf9U6QsRKpmeNj1x06K4vsyMKtU3/iZdwZEz8b7MWY\n44AxcCgNSX+A8icJAoGAI3VnVV+gjD7NdnBcNAZv66Fe/qv24J6WeOAMzvxOkS4sVx7HOnCu\nqAkgvM37hyrIp0phRZerEkTuai3TErpRFE2mZgqTQlbtvsMGN7jXVYmDt6Yt5BuRLaFCiteZ\nzi/U0ybsSu+p/OpjRGrbnvwWCekXUJDo4W2t5QCM27XHP1ECgYBbKYbcswxeBha2au4Cj3cf\nz7oW5khGNziJELJSG8ulUNtR0LkfS429JXWjo3qYVYPBeEPePoYE1qcrDnSQesYt2yq1y5Uh\nJjwAxK1wVGw9UcQl0w/utuDxcGCArlszFcRNPX1g/5e0F07OXM8bF9gQcom1HZBKgLaoLStI\nz94OOA==\n-----END RSA PRIVATE KEY-----\n',
pubKey: '-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAgPEiGHOwFEUdo95/DaALH69umbFI4xD3Jmla0hiHbkcW535arBfFd8nJs5VP\nt49sgdSgn1ZmiqmHLgMwMz6mKplu4GsmWj5mjdyxiNl5z6R2rF+ZziuiwRTeHVX/8zR8M7Cb\nh0QXmzpoq6LcNOFHbg495zsbmT9QAtjVsS1KyF5324mxbTZtjaD6hxJkAL8aVi0ikvhAL4Hu\nZ1m3brjSSZ0+epFCFL7UIoJlFfOvap2sAyxdOrSvY2PXKTE00s51YTin5+CrvofRLCJPROls\n1oFkhXIDGfuTGTxMxe3hSUlNj0LjQi6RXPGat/5XH0nCuFTODmyhrnnnx51OdgT9vwIDAQAB\n-----END RSA PUBLIC KEY-----\n'
privKey: 'CAASqQkwggSlAgEAAoIBAQC1/m95i4waplpSl43/uefQClPfuguPsX6qa6pWE0Df+krs5p+RnhX+8j2aWBI9QZ0pliGryet5qM3in6J1ihb2LzjLUWIsWrMLxtqi/mQDjj1f0HfV11Q/k2v6yVgSgYJ+VoW51hCpAEdEnhthsbyKWMD6xVIvtkqOmK/FaxUMa2boWCVKsycf39U6GVaiuTk32btw6LqGMo8P1cehWDy80SOzv0qk2mD7ZJbKnVfVm8xwU+gzogasOFYs/LmKb4IEV9Otq0MHmWGUN0VyC82htoGBidheRs1Ssh7TDVtWlNTJSG1vJJV7cnIhpGKut2b0pMxhY1Sg0kn/VrfriXINAgMBAAECggEBAJrJuI4r/hF8gz3T4NYri9oJrqSOW97vG8heohVrcrYM70TmMblsN1ELPxHS7lBjSgRgyGqP5lMnG1UwaMCHnlfseeWTZmhLDBVsH/CZZP8RL2oaqJGb/u/Dtwcp0FqNBCvn8vzH8IuMzRCzWJ6SyMTyD9A5m1kxNeBqRLUoClLwZsLKuL8ld9sXfwmn1D1yY9sWLWCcrlPZnm4v49otc6Q9GYpurhOLBlQOqkEVqSyiN9N70bZ3QNPxWpAjKZS08X5PK0teI0b3uMZB9KwCdPkjMxHyymulyQ/bOkm1CCogFpGlG8abwyusIfrrjQOCeX+sUSei6/K/eN2kPLUUcoECgYEA0EKwQPq6mXmXiWqVMk08wz1JPqiNE9zreqaSOx9aOO/DbeR0xkfWjKy4RoCY9zo8FW0Y7jvwuEojm7LNZSrLrur3b2myfzHsdsjuo2t/fVilVrjtzxDEQSeBNOJasVdS+ZhB+/GHWfeZEcMjhXHkW9WRgMwIC/jTanmqLYy4nzkCgYEA37ZZJ+QH8+saafhztaSK/IC8pjJLTkHsMBjhSpVGm9TptpVdxHx/cHJdCDiHPfeP+TIPSOD//hGbHoTZuy2owZ0FJ2QFxyLpagEUch+Sy0f7fQZ+LoeUa1UJ9RsCbCCeKtcZvqZ0fuu9iWoR8LvJ7UI19SEyQ2T7Fymvbq3hFXUCgYEAsHHf7J3BHKjE97rifwSrV2sENF8Pb+W7aGXZ/NdaVGTm+aMWQKu6neL0GV94ufWP1ENjXOxRzYGa255IoM76VM9kJfOyNEuy4QzqCnDYSfWh13DEoqu86sqykIC6gAfRGACk3vVKTLIW8NKYtMXCyP+P0ESNCL+fN1WvFfpkrRkCgYEA3nriP6GvpwxwwGKt8D8rWeJNuprZ+YHl+g9EPoAmMGOV6laxYe7Obm3Nx5cwKJhDPnhiawAYlfu8YKWOQ3AtHB+kOIBonppBt4JLaxOrUS7NFJGYe32qRPPVa0TpK89kfQZePBQeVvrrC/XI0bhwINxv/NB+xDdw3qA+L7wM1OECgYA+3YgYJ6nbvT7s4DylRmyZ4AfOt3TcIjS3D0PDj4S4agZrvlPCKgn1LwBIFutjOe6V9lPSWZJiw6flfImhpWvQOap3zdT9gsU5PhbUmD3TndAk0n10+lmMYpGkU2UM/+zV5HsiZA5X+DPcVbSnIuNT/7pZdbD5uFF9Ibzoh022Fg==',
pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1/m95i4waplpSl43/uefQClPfuguPsX6qa6pWE0Df+krs5p+RnhX+8j2aWBI9QZ0pliGryet5qM3in6J1ihb2LzjLUWIsWrMLxtqi/mQDjj1f0HfV11Q/k2v6yVgSgYJ+VoW51hCpAEdEnhthsbyKWMD6xVIvtkqOmK/FaxUMa2boWCVKsycf39U6GVaiuTk32btw6LqGMo8P1cehWDy80SOzv0qk2mD7ZJbKnVfVm8xwU+gzogasOFYs/LmKb4IEV9Otq0MHmWGUN0VyC82htoGBidheRs1Ssh7TDVtWlNTJSG1vJJV7cnIhpGKut2b0pMxhY1Sg0kn/VrfriXINAgMBAAE='
}
var testIdHex = '1220151ab1658d8294ab34b71d5582cfe20d06414212f440a69366f1bc31deb5c72d'
@ -15,6 +15,7 @@ var testIdB58String = 'QmPm2sunRFpswBAByqunK5Yk8PLj7mxL5HpCS4Qg6p7LdS'
test('create a new Id', function (t) {
var id = PeerId.create()
console.log(id.toPrint())
t.ok(id)
t.end()
})
@ -39,12 +40,12 @@ test('Recreate an B58 String', function (t) {
test('Recreate from a Public Key', function (t) {
var id = PeerId.createFromPubKey(testId.pubKey)
t.ok(id)
t.ok(id.pubKey == testId.pubKey)
t.end()
})
test('Recreate from a Private Key', function (t) {
var id = PeerId.createFromPrivKey(testId.privKey)
t.ok(id)
t.ok(id.pubKey == testId.pubKey)
t.end()
})