mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-03-15 08:41:05 +00:00
feat: improve perf (#117)
This commit is contained in:
parent
2c0dc706b7
commit
cdcca5f828
@ -34,10 +34,10 @@
|
||||
"async": "^2.6.0",
|
||||
"browserify-aes": "^1.1.1",
|
||||
"bs58": "^4.0.1",
|
||||
"jsrsasign": "^8.0.4",
|
||||
"keypair": "^1.0.1",
|
||||
"libp2p-crypto-secp256k1": "~0.2.2",
|
||||
"multihashing-async": "~0.4.7",
|
||||
"node-forge": "^0.7.1",
|
||||
"pem-jwk": "^1.5.1",
|
||||
"protons": "^1.0.1",
|
||||
"rsa-pem-to-jwk": "^1.1.3",
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
const protobuf = require('protons')
|
||||
const keysPBM = protobuf(require('./keys.proto'))
|
||||
const jsrsasign = require('jsrsasign')
|
||||
const KEYUTIL = jsrsasign.KEYUTIL
|
||||
const forge = require('node-forge')
|
||||
|
||||
exports = module.exports
|
||||
|
||||
@ -120,13 +119,13 @@ exports.marshalPrivateKey = (key, type) => {
|
||||
|
||||
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()}'`)
|
||||
const key = forge.pki.decryptRsaPrivateKey(pem, password)
|
||||
if (key === null) {
|
||||
throw new Error('Cannot read the key, most likely the password is wrong or not a RSA key')
|
||||
}
|
||||
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
|
||||
der = Buffer.from(der.getBytes(), 'binary')
|
||||
return supportedKeys.rsa.unmarshalRsaPrivateKey(der, callback)
|
||||
} catch (err) {
|
||||
callback(err)
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ const bs58 = require('bs58')
|
||||
|
||||
const crypto = require('./rsa')
|
||||
const pbm = protobuf(require('./keys.proto'))
|
||||
const KEYUTIL = require('jsrsasign').KEYUTIL
|
||||
const forge = require('node-forge')
|
||||
const setImmediate = require('async/setImmediate')
|
||||
|
||||
class RsaPublicKey {
|
||||
@ -127,20 +127,29 @@ class RsaPrivateKey {
|
||||
format = 'pkcs-8'
|
||||
}
|
||||
|
||||
setImmediate(() => {
|
||||
ensure(callback)
|
||||
ensure(callback)
|
||||
|
||||
setImmediate(() => {
|
||||
let err = null
|
||||
let pem = null
|
||||
try {
|
||||
const key = KEYUTIL.getKey(this._key) // _key is a JWK (JSON Web Key)
|
||||
const buffer = new forge.util.ByteBuffer(this.marshal())
|
||||
const asn1 = forge.asn1.fromDer(buffer)
|
||||
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
|
||||
|
||||
if (format === 'pkcs-8') {
|
||||
pem = KEYUTIL.getPEM(key, 'PKCS8PRV', password)
|
||||
const options = {
|
||||
algorithm: 'aes256',
|
||||
count: 10000,
|
||||
saltSize: 128 / 8,
|
||||
prfAlgorithm: 'sha512'
|
||||
}
|
||||
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
|
||||
} else {
|
||||
err = new Error(`Unknown export format '${format}'`)
|
||||
}
|
||||
} catch (e) {
|
||||
err = e
|
||||
} catch (_err) {
|
||||
err = _err
|
||||
}
|
||||
|
||||
callback(err, pem)
|
||||
@ -150,6 +159,7 @@ class RsaPrivateKey {
|
||||
|
||||
function unmarshalRsaPrivateKey (bytes, callback) {
|
||||
const jwk = crypto.utils.pkcs1ToJwk(bytes)
|
||||
|
||||
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
@ -175,18 +185,18 @@ function fromJwk (jwk, callback) {
|
||||
})
|
||||
}
|
||||
|
||||
function generateKeyPair (bits, cb) {
|
||||
function generateKeyPair (bits, callback) {
|
||||
crypto.generateKey(bits, (err, keys) => {
|
||||
if (err) {
|
||||
return cb(err)
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
cb(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
|
||||
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
|
||||
})
|
||||
}
|
||||
|
||||
function ensure (cb) {
|
||||
if (typeof cb !== 'function') {
|
||||
function ensure (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error('callback is required')
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const crypto = require('jsrsasign').CryptoJS
|
||||
const forge = require('node-forge')
|
||||
|
||||
/**
|
||||
* Maps an IPFS hash name to its jsrsasign equivalent.
|
||||
* Maps an IPFS hash name to its node-forge equivalent.
|
||||
*
|
||||
* See https://github.com/multiformats/multihash/blob/master/hashtable.csv
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const hashName = {
|
||||
sha1: crypto.algo.SHA1,
|
||||
'sha2-256': crypto.algo.SHA256,
|
||||
'sha2-512': crypto.algo.SHA512
|
||||
sha1: 'sha1',
|
||||
'sha2-256': 'sha256',
|
||||
'sha2-512': 'sha512'
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,16 +26,17 @@ const hashName = {
|
||||
* @returns {string} - A new password
|
||||
*/
|
||||
function pbkdf2 (password, salt, iterations, keySize, hash) {
|
||||
const opts = {
|
||||
iterations: iterations,
|
||||
keySize: keySize / 4, // convert bytes to words (32 bits)
|
||||
hasher: hashName[hash]
|
||||
}
|
||||
if (!opts.hasher) {
|
||||
const hasher = hashName[hash]
|
||||
if (!hasher) {
|
||||
throw new Error(`Hash '${hash}' is unknown or not supported`)
|
||||
}
|
||||
const words = crypto.PBKDF2(password, salt, opts)
|
||||
return crypto.enc.Base64.stringify(words)
|
||||
const dek = forge.pkcs5.pbkdf2(
|
||||
password,
|
||||
salt,
|
||||
iterations,
|
||||
keySize,
|
||||
hasher)
|
||||
return forge.util.encode64(dek)
|
||||
}
|
||||
|
||||
module.exports = pbkdf2
|
||||
|
@ -13,7 +13,7 @@ describe('libp2p-crypto', function () {
|
||||
this.timeout(20 * 1000)
|
||||
let key
|
||||
before((done) => {
|
||||
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
|
||||
crypto.keys.generateKeyPair('RSA', 512, (err, _key) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ describe('RSA', function () {
|
||||
let key
|
||||
|
||||
before((done) => {
|
||||
crypto.keys.generateKeyPair('RSA', 2048, (err, _key) => {
|
||||
crypto.keys.generateKeyPair('RSA', 512, (err, _key) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
@ -97,7 +97,7 @@ describe('RSA', function () {
|
||||
})
|
||||
|
||||
it('not equals other key', (done) => {
|
||||
crypto.keys.generateKeyPair('RSA', 2048, (err, key2) => {
|
||||
crypto.keys.generateKeyPair('RSA', 512, (err, key2) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
@ -297,8 +297,42 @@ mBdkD5r+ixWF174naw53L8U9wF8kiK7pIE1N9TR4USEeovLwX6Ni/2MMDZedOfof
|
||||
})
|
||||
})
|
||||
|
||||
// AssertionError: expected 'this only supports TripleDES' to not exist
|
||||
it.skip('can read a private encrypted key (v2 aes-256-cbc)', (done) => {
|
||||
it('can read a private encrypted key (v2 aes-128-cbc)', (done) => {
|
||||
/*
|
||||
* Generated with
|
||||
* openssl genpkey -algorithm RSA
|
||||
* -pkeyopt rsa_keygen_bits:1024
|
||||
* -pkeyopt rsa_keygen_pubexp:65537
|
||||
* -out foo.pem
|
||||
* openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword
|
||||
*/
|
||||
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP5QK2RfqUl4CAggA
|
||||
MB0GCWCGSAFlAwQBAgQQj3OyM9gnW2dd/eRHkxjGrgSCAoCpM5GZB0v27cxzZsGc
|
||||
O4/xqgwB0c/bSJ6QogtYU2KVoc7ZNQ5q9jtzn3I4ONvneOkpm9arzYz0FWnJi2C3
|
||||
BPiF0D1NkfvjvMLv56bwiG2A1oBECacyAb2pXYeJY7SdtYKvcbgs3jx65uCm6TF2
|
||||
BylteH+n1ewTQN9DLfASp1n81Ajq9lQGaK03SN2MUtcAPp7N9gnxJrlmDGeqlPRs
|
||||
KpQYRcot+kE6Ew8a5jAr7mAxwpqvr3SM4dMvADZmRQsM4Uc/9+YMUdI52DG87EWc
|
||||
0OUB+fnQ8jw4DZgOE9KKM5/QTWc3aEw/dzXr/YJsrv01oLazhqVHnEMG0Nfr0+DP
|
||||
q+qac1AsCsOb71VxaRlRZcVEkEfAq3gidSPD93qmlDrCnmLYTilcLanXUepda7ez
|
||||
qhjkHtpwBLN5xRZxOn3oUuLGjk8VRwfmFX+RIMYCyihjdmbEDYpNUVkQVYFGi/F/
|
||||
1hxOyl9yhGdL0hb9pKHH10GGIgoqo4jSTLlb4ennihGMHCjehAjLdx/GKJkOWShy
|
||||
V9hj8rAuYnRNb+tUW7ChXm1nLq14x9x1tX0ciVVn3ap/NoMkbFTr8M3pJ4bQlpAn
|
||||
wCT2erYqwQtgSpOJcrFeph9TjIrNRVE7Zlmr7vayJrB/8/oPssVdhf82TXkna4fB
|
||||
PcmO0YWLa117rfdeNM/Duy0ThSdTl39Qd+4FxqRZiHjbt+l0iSa/nOjTv1TZ/QqF
|
||||
wqrO6EtcM45fbFJ1Y79o2ptC2D6MB4HKJq9WCt064/8zQCVx3XPbb3X8Z5o/6koy
|
||||
ePGbz+UtSb9xczvqpRCOiFLh2MG1dUgWuHazjOtUcVWvilKnkjCMzZ9s1qG0sUDj
|
||||
nPyn
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
crypto.keys.import(pem, 'mypassword', (err, key) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(key).to.exist()
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('can read a private encrypted key (v2 aes-256-cbc)', (done) => {
|
||||
/*
|
||||
* Generated with
|
||||
* openssl genpkey -algorithm RSA
|
||||
@ -333,6 +367,40 @@ DQd8
|
||||
})
|
||||
})
|
||||
|
||||
it('can read a private encrypted key (v2 des)', (done) => {
|
||||
/*
|
||||
* Generated with
|
||||
* openssl genpkey -algorithm RSA
|
||||
* -pkeyopt rsa_keygen_bits:1024
|
||||
* -pkeyopt rsa_keygen_pubexp:65537
|
||||
* -out foo.pem
|
||||
* openssl pkcs8 -in foo.pem -topk8 -v2 des -passout pass:mypassword
|
||||
*/
|
||||
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIICwzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQI0lXp62ozXvwCAggA
|
||||
MBEGBSsOAwIHBAiR3Id5vH0u4wSCAoDQQYOrrkPFPIa0S5fQGXnJw1F/66g92Gs1
|
||||
TkGydn4ouabWb++Vbi2chee1oyZsN2l8YNzDi0Gb2PfjsGpg2aJk0a3/efgA0u6T
|
||||
leEH1dA/7Hr9NVspgHkaXpHt3X6wdbznLYJeAelfj7sDXpOkULGWCkCst0Txb6bi
|
||||
Oxv4c0yYykiuUrp+2xvHbF9c2PrcDb58u/OBZcCg3QB1gTugQKM+ZIBRhcTEFLrm
|
||||
8gWbzBfwYiUm6aJce4zoafP0NSlEOBbpbr73A08Q1IK6pISwltOUhhTvspSZnK41
|
||||
y2CHt5Drnpl1pfOw9Q0svO3VrUP+omxP1SFP17ZfaRGw2uHd08HJZs438x5dIQoH
|
||||
QgjlZ8A5rcT3FjnytSh3fln2ZxAGuObghuzmOEL/+8fkGER9QVjmQlsL6OMfB4j4
|
||||
ZAkLf74uaTdegF3SqDQaGUwWgk7LyualmUXWTBoeP9kRIsRQLGzAEmd6duBPypED
|
||||
HhKXP/ZFA1kVp3x1fzJ2llMFB3m1JBwy4PiohqrIJoR+YvKUvzVQtbOjxtCEAj87
|
||||
JFnlQj0wjTd6lfNn+okewMNjKINZx+08ui7XANNU/l18lHIIz3ssXJSmqMW+hRZ9
|
||||
9oB2tntLrnRMhkVZDVHadq7eMFOPu0rkekuaZm9CO2vu4V7Qa2h+gOoeczYza0H7
|
||||
A+qCKbprxyL8SKI5vug2hE+mfC1leXVRtUYm1DnE+oet99bFd0fN20NwTw0rOeRg
|
||||
0Z+/ZpQNizrXxfd3sU7zaJypWCxZ6TD/U/AKBtcb2gqmUjObZhbfbWq6jU2Ye//w
|
||||
EBqQkwAUXR1tNekF8CWLOrfC/wbLRxVRkayb8bQUfdgukLpz0bgw
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
crypto.keys.import(pem, 'mypassword', (err, key) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(key).to.exist()
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('can read a private encrypted key (v2 des3)', (done) => {
|
||||
/*
|
||||
* Generated with
|
||||
|
Loading…
x
Reference in New Issue
Block a user