feat: key exchange with jsrsasign (#115)

* feat: export/import password protected RSA key

* docs: crypto.key.import

* test: import with wrong password

* fix: lint

* test: importing openssl keys

* just to trigger circle with new ubuntu

* feat: get the RSA key id

* feat: get the ED 25519 key id

* feat: pbkdf2

* fix(pbkdf2): base64 has more chars to guess than hex

* chore: update deps
This commit is contained in:
Richard Schneider
2017-12-20 21:11:47 +13:00
committed by David Dias
parent f3cb8ced36
commit b3421284f9
11 changed files with 423 additions and 7 deletions

View File

@ -2,6 +2,7 @@
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const bs58 = require('bs58')
const crypto = require('./ed25519')
const pbm = protobuf(require('./keys.proto'))
@ -77,6 +78,25 @@ class Ed25519PrivateKey {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @param {function(Error, id)} callback
* @returns {undefined}
*/
id (callback) {
this.public.hash((err, hash) => {
if (err) {
return callback(err)
}
callback(null, bs58.encode(hash))
})
}
}
function unmarshalEd25519PrivateKey (bytes, callback) {

View File

@ -2,6 +2,8 @@
const protobuf = require('protons')
const keysPBM = protobuf(require('./keys.proto'))
const jsrsasign = require('jsrsasign')
const KEYUTIL = jsrsasign.KEYUTIL
exports = module.exports
@ -115,3 +117,17 @@ exports.marshalPrivateKey = (key, type) => {
return key.bytes
}
exports.import = (pem, password, callback) => {
try {
const key = KEYUTIL.getKey(pem, password)
if (key instanceof jsrsasign.RSAKey) {
const jwk = KEYUTIL.getJWKFromKey(key)
return supportedKeys.rsa.fromJwk(jwk, callback)
} else {
throw new Error(`Unknown key type '${key.prototype.toString()}'`)
}
} catch (err) {
callback(err)
}
}

View File

@ -105,9 +105,7 @@ function derivePublicFromPrivate (jwKey) {
{
kty: jwKey.kty,
n: jwKey.n,
e: jwKey.e,
alg: jwKey.alg,
kid: jwKey.kid
e: jwKey.e
},
{
name: 'RSASSA-PKCS1-v1_5',

View File

@ -2,9 +2,12 @@
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const bs58 = require('bs58')
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
const KEYUTIL = require('jsrsasign').KEYUTIL
const setImmediate = require('async/setImmediate')
class RsaPublicKey {
constructor (key) {
@ -89,6 +92,60 @@ class RsaPrivateKey {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @param {function(Error, id)} callback
* @returns {undefined}
*/
id (callback) {
this.public.hash((err, hash) => {
if (err) {
return callback(err)
}
callback(null, bs58.encode(hash))
})
}
/**
* Exports the key into a password protected PEM format
*
* @param {string} [format] - Defaults to 'pkcs-8'.
* @param {string} password - The password to read the encrypted PEM
* @param {function(Error, KeyInfo)} callback
* @returns {undefined}
*/
export (format, password, callback) {
if (typeof password === 'function') {
callback = password
password = format
format = 'pkcs-8'
}
setImmediate(() => {
ensure(callback)
let err = null
let pem = null
try {
const key = KEYUTIL.getKey(this._key) // _key is a JWK (JSON Web Key)
if (format === 'pkcs-8') {
pem = KEYUTIL.getPEM(key, 'PKCS8PRV', password)
} else {
err = new Error(`Unknown export format '${format}'`)
}
} catch (e) {
err = e
}
callback(err, pem)
})
}
}
function unmarshalRsaPrivateKey (bytes, callback) {
@ -108,6 +165,16 @@ function unmarshalRsaPublicKey (bytes) {
return new RsaPublicKey(jwk)
}
function fromJwk (jwk, callback) {
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
}
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
}
function generateKeyPair (bits, cb) {
crypto.generateKey(bits, (err, keys) => {
if (err) {
@ -129,5 +196,6 @@ module.exports = {
RsaPrivateKey,
unmarshalRsaPublicKey,
unmarshalRsaPrivateKey,
generateKeyPair
generateKeyPair,
fromJwk
}