Refactor keygen to use promises (Work in progress)
This commit is contained in:
parent
5d07ee1eb1
commit
0ac58356b5
|
@ -178,19 +178,14 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
|
||||
generateMpi: function(algo, bits, callback) {
|
||||
generateMpi: function(algo, bits) {
|
||||
switch (algo) {
|
||||
case 'rsa_encrypt':
|
||||
case 'rsa_encrypt_sign':
|
||||
case 'rsa_sign':
|
||||
//remember "publicKey" refers to the crypto/public_key dir
|
||||
var rsa = new publicKey.rsa();
|
||||
rsa.generate(bits, "10001", function(err, keyObject) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
return rsa.generate(bits, "10001").then(function(keyObject) {
|
||||
var output = [];
|
||||
output.push(keyObject.n);
|
||||
output.push(keyObject.ee);
|
||||
|
@ -198,12 +193,10 @@ module.exports = {
|
|||
output.push(keyObject.p);
|
||||
output.push(keyObject.q);
|
||||
output.push(keyObject.u);
|
||||
|
||||
callback(null, mapResult(output));
|
||||
return mapResult(output);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
callback(new Error('Unsupported algorithm for key generation.'));
|
||||
throw new Error('Unsupported algorithm for key generation.');
|
||||
}
|
||||
|
||||
function mapResult(result) {
|
||||
|
|
|
@ -133,8 +133,9 @@ function RSA() {
|
|||
|
||||
// Generate a new random private key B bits long, using public expt E
|
||||
|
||||
function generate(B, E, callback) {
|
||||
function generate(B, E) {
|
||||
var webCrypto = util.getWebCrypto();
|
||||
var promise;
|
||||
|
||||
//
|
||||
// Native RSA keygen using Web Crypto
|
||||
|
@ -143,7 +144,6 @@ function RSA() {
|
|||
if (webCrypto) {
|
||||
var Euint32 = new Uint32Array([parseInt(E, 16)]); // get integer of exponent
|
||||
var Euint8 = new Uint8Array(Euint32.buffer); // get bytes of exponent
|
||||
|
||||
var keyGenOpt = {
|
||||
name: 'RSASSA-PKCS1-v1_5',
|
||||
modulusLength: B, // the specified keysize in bits
|
||||
|
@ -152,11 +152,8 @@ function RSA() {
|
|||
name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify'
|
||||
}
|
||||
};
|
||||
|
||||
var gen = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
|
||||
gen.then(exportKey).then(decodeKey).catch(onError);
|
||||
|
||||
return;
|
||||
promise = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
|
||||
return promise.then(exportKey).then(decodeKey);
|
||||
}
|
||||
|
||||
function exportKey(key) {
|
||||
|
@ -181,52 +178,53 @@ function RSA() {
|
|||
return new BigInteger(hex, 16);
|
||||
}
|
||||
|
||||
callback(null, key);
|
||||
}
|
||||
|
||||
function onError() {
|
||||
callback(new Error('Generating key failed!'));
|
||||
return key;
|
||||
}
|
||||
|
||||
//
|
||||
// JS code
|
||||
//
|
||||
|
||||
var key = new keyObject();
|
||||
var rng = new SecureRandom();
|
||||
var qs = B >> 1;
|
||||
key.e = parseInt(E, 16);
|
||||
key.ee = new BigInteger(E, 16);
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
key.p = new BigInteger(B - qs, 1, rng);
|
||||
if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.p.isProbablePrime(10))
|
||||
break;
|
||||
}
|
||||
for (;;) {
|
||||
key.q = new BigInteger(qs, 1, rng);
|
||||
if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.q.isProbablePrime(10))
|
||||
break;
|
||||
}
|
||||
if (key.p.compareTo(key.q) <= 0) {
|
||||
var t = key.p;
|
||||
key.p = key.q;
|
||||
key.q = t;
|
||||
}
|
||||
var p1 = key.p.subtract(BigInteger.ONE);
|
||||
var q1 = key.q.subtract(BigInteger.ONE);
|
||||
var phi = p1.multiply(q1);
|
||||
if (phi.gcd(key.ee).compareTo(BigInteger.ONE) === 0) {
|
||||
key.n = key.p.multiply(key.q);
|
||||
key.d = key.ee.modInverse(phi);
|
||||
key.dmp1 = key.d.mod(p1);
|
||||
key.dmq1 = key.d.mod(q1);
|
||||
key.u = key.p.modInverse(key.q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
promise = new Promise(function(resolve) {
|
||||
var key = new keyObject();
|
||||
var rng = new SecureRandom();
|
||||
var qs = B >> 1;
|
||||
key.e = parseInt(E, 16);
|
||||
key.ee = new BigInteger(E, 16);
|
||||
|
||||
callback(null, key);
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
key.p = new BigInteger(B - qs, 1, rng);
|
||||
if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.p.isProbablePrime(10))
|
||||
break;
|
||||
}
|
||||
for (;;) {
|
||||
key.q = new BigInteger(qs, 1, rng);
|
||||
if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.q.isProbablePrime(10))
|
||||
break;
|
||||
}
|
||||
if (key.p.compareTo(key.q) <= 0) {
|
||||
var t = key.p;
|
||||
key.p = key.q;
|
||||
key.q = t;
|
||||
}
|
||||
var p1 = key.p.subtract(BigInteger.ONE);
|
||||
var q1 = key.q.subtract(BigInteger.ONE);
|
||||
var phi = p1.multiply(q1);
|
||||
if (phi.gcd(key.ee).compareTo(BigInteger.ONE) === 0) {
|
||||
key.n = key.p.multiply(key.q);
|
||||
key.d = key.ee.modInverse(phi);
|
||||
key.dmp1 = key.d.mod(p1);
|
||||
key.dmq1 = key.d.mod(q1);
|
||||
key.u = key.p.modInverse(key.q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resolve(key);
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
this.encrypt = encrypt;
|
||||
|
|
49
src/key.js
49
src/key.js
|
@ -5,7 +5,7 @@
|
|||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
//
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
|
@ -910,7 +910,7 @@ function readArmored(armoredText) {
|
|||
* @return {module:key~Key}
|
||||
* @static
|
||||
*/
|
||||
function generate(options, callback) {
|
||||
function generate(options) {
|
||||
var packetlist, secretKeyPacket, userIdPacket, dataToSign, signaturePacket, secretSubkeyPacket, subkeySignaturePacket;
|
||||
|
||||
options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign;
|
||||
|
@ -923,22 +923,32 @@ function generate(options, callback) {
|
|||
options.unlocked = true;
|
||||
}
|
||||
|
||||
packetlist = new packet.List();
|
||||
// generate
|
||||
var genSecretKey = generateSecretKey();
|
||||
var genSecretSubkey = generateSecretSubkey();
|
||||
return Promise.all([genSecretKey, genSecretSubkey]).then(wrapKeyObject);
|
||||
|
||||
secretKeyPacket = new packet.SecretKey();
|
||||
secretKeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
|
||||
secretKeyPacket.generate(options.numBits, onSecretKeyGenerated);
|
||||
function generateSecretKey() {
|
||||
secretKeyPacket = new packet.SecretKey();
|
||||
secretKeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
|
||||
return secretKeyPacket.generate(options.numBits);
|
||||
}
|
||||
|
||||
function onSecretKeyGenerated(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
function generateSecretSubkey() {
|
||||
secretSubkeyPacket = new packet.SecretSubkey();
|
||||
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
|
||||
return secretSubkeyPacket.generate(options.numBits);
|
||||
}
|
||||
|
||||
function wrapKeyObject() {
|
||||
// set passphrase protection
|
||||
if (options.passphrase) {
|
||||
secretKeyPacket.encrypt(options.passphrase);
|
||||
secretSubkeyPacket.encrypt(options.passphrase);
|
||||
}
|
||||
|
||||
packetlist = new packet.List();
|
||||
|
||||
userIdPacket = new packet.Userid();
|
||||
userIdPacket.read(options.userId);
|
||||
|
||||
|
@ -969,21 +979,6 @@ function generate(options, callback) {
|
|||
}
|
||||
signaturePacket.sign(secretKeyPacket, dataToSign);
|
||||
|
||||
secretSubkeyPacket = new packet.SecretSubkey();
|
||||
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
|
||||
secretSubkeyPacket.generate(options.numBits, onSecretSubkeyGenerated);
|
||||
}
|
||||
|
||||
function onSecretSubkeyGenerated(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.passphrase) {
|
||||
secretSubkeyPacket.encrypt(options.passphrase);
|
||||
}
|
||||
|
||||
dataToSign = {};
|
||||
dataToSign.key = secretKeyPacket;
|
||||
dataToSign.bind = secretSubkeyPacket;
|
||||
|
@ -1005,7 +1000,7 @@ function generate(options, callback) {
|
|||
secretSubkeyPacket.clearPrivateMPIs();
|
||||
}
|
||||
|
||||
callback(null, new Key(packetlist));
|
||||
return new Key(packetlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -229,28 +229,23 @@ function verifyClearSignedMessage(publicKeys, msg, callback) {
|
|||
* @return {Object} {key: module:key~Key, privateKeyArmored: String, publicKeyArmored: String}
|
||||
* @static
|
||||
*/
|
||||
function generateKeyPair(options, callback) {
|
||||
if (!callback) {
|
||||
throw new Error('Callback must be set for key generation!');
|
||||
}
|
||||
|
||||
function generateKeyPair(options) {
|
||||
// use web worker if web crypto apis are not supported
|
||||
if (!util.getWebCrypto() && useWorker(callback)) {
|
||||
asyncProxy.generateKeyPair(options, callback);
|
||||
if (!util.getWebCrypto() && useWorker()) {
|
||||
asyncProxy.generateKeyPair(options);
|
||||
return;
|
||||
}
|
||||
|
||||
key.generate(options, function(err, newKey) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
return key.generate(options).then(function(newKey) {
|
||||
var result = {};
|
||||
result.key = newKey;
|
||||
result.privateKeyArmored = newKey.armor();
|
||||
result.publicKeyArmored = newKey.toPublic().armor();
|
||||
callback(null, result);
|
||||
return result;
|
||||
|
||||
}).catch(function(err) {
|
||||
console.error(err.stack);
|
||||
throw new Error('Error generating keypair!');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
//
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
|
@ -270,18 +270,12 @@ SecretKey.prototype.decrypt = function (passphrase) {
|
|||
return true;
|
||||
};
|
||||
|
||||
SecretKey.prototype.generate = function (bits, callback) {
|
||||
SecretKey.prototype.generate = function (bits) {
|
||||
var self = this;
|
||||
|
||||
crypto.generateMpi(self.algorithm, bits, function(err, mpi) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
return crypto.generateMpi(self.algorithm, bits).then(function(mpi) {
|
||||
self.mpi = mpi;
|
||||
self.isDecrypted = true;
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -417,8 +417,8 @@ describe('High level API', function() {
|
|||
describe('Key generation', function() {
|
||||
|
||||
it('Generate 1024-bit RSA/RSA key async', function (done) {
|
||||
openpgp.generateKeyPair({numBits: 1024, userId: 'Test McTestington <test@example.com>', passphrase: 'hello world'}, function(err, data) {
|
||||
expect(err).to.not.exist;
|
||||
var opt = {numBits: 1024, userId: 'Test McTestington <test@example.com>', passphrase: 'hello world'};
|
||||
openpgp.generateKeyPair(opt).then(function(data) {
|
||||
expect(data).to.exist;
|
||||
expect(data.publicKeyArmored).to.match(/^-----BEGIN PGP PUBLIC/);
|
||||
expect(data.privateKeyArmored).to.match(/^-----BEGIN PGP PRIVATE/);
|
||||
|
|
Loading…
Reference in New Issue
Block a user