Generate key by default without unlocking secret part. Use options parameter for generate method.

This commit is contained in:
Thomas Oberndörfer 2014-04-28 16:15:27 +02:00
parent fd25743082
commit bb0ac83cb7
8 changed files with 58 additions and 35 deletions

View File

@ -928,36 +928,41 @@ function readArmored(armoredText) {
/**
* Generates a new OpenPGP key. Currently only supports RSA keys.
* Primary and subkey will be of same type.
* @param {module:enums.publicKey} keyType to indicate what type of key to make.
* @param {module:enums.publicKey} [options.keyType=module:enums.publicKey.rsa_encrypt_sign] to indicate what type of key to make.
* RSA is 1. See {@link http://tools.ietf.org/html/rfc4880#section-9.1}
* @param {Integer} numBits number of bits for the key creation.
* @param {String} userId assumes already in form of "User Name <username@email.com>"
* @param {String} passphrase The passphrase used to encrypt the resulting private key
* @param {Integer} options.numBits number of bits for the key creation.
* @param {String} options.userId assumes already in form of "User Name <username@email.com>"
* @param {String} options.passphrase The passphrase used to encrypt the resulting private key
* @param {Boolean} [options.unlocked=false] The secret part of the generated key is unlocked
* @return {module:key~Key}
* @static
*/
function generate(keyType, numBits, userId, passphrase) {
function generate(options) {
options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign;
// RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
if (keyType !== enums.publicKey.rsa_encrypt_sign) {
if (options.keyType !== enums.publicKey.rsa_encrypt_sign) {
throw new Error('Only RSA Encrypt or Sign supported');
}
if (!options.passphrase) {
throw new Error('Parameter options.passphrase required');
}
var packetlist = new packet.List();
var secretKeyPacket = new packet.SecretKey();
secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType);
secretKeyPacket.generate(numBits);
secretKeyPacket.encrypt(passphrase);
secretKeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
secretKeyPacket.generate(options.numBits);
secretKeyPacket.encrypt(options.passphrase);
var userIdPacket = new packet.Userid();
userIdPacket.read(userId);
userIdPacket.read(options.userId);
var dataToSign = {};
dataToSign.userid = userIdPacket;
dataToSign.key = secretKeyPacket;
var signaturePacket = new packet.Signature();
signaturePacket.signatureType = enums.signature.cert_generic;
signaturePacket.publicKeyAlgorithm = keyType;
signaturePacket.publicKeyAlgorithm = options.keyType;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.preferredSymmetricAlgorithms = [];
@ -980,16 +985,16 @@ function generate(keyType, numBits, userId, passphrase) {
signaturePacket.sign(secretKeyPacket, dataToSign);
var secretSubkeyPacket = new packet.SecretSubkey();
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType);
secretSubkeyPacket.generate(numBits);
secretSubkeyPacket.encrypt(passphrase);
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
secretSubkeyPacket.generate(options.numBits);
secretSubkeyPacket.encrypt(options.passphrase);
dataToSign = {};
dataToSign.key = secretKeyPacket;
dataToSign.bind = secretSubkeyPacket;
var subkeySignaturePacket = new packet.Signature();
subkeySignaturePacket.signatureType = enums.signature.subkey_binding;
subkeySignaturePacket.publicKeyAlgorithm = keyType;
subkeySignaturePacket.publicKeyAlgorithm = options.keyType;
subkeySignaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage];
subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
@ -1000,6 +1005,11 @@ function generate(keyType, numBits, userId, passphrase) {
packetlist.push(secretSubkeyPacket);
packetlist.push(subkeySignaturePacket);
if (!options.unlocked) {
secretKeyPacket.clearPrivateMPIs();
secretSubkeyPacket.clearPrivateMPIs();
}
return new Key(packetlist);
}

View File

@ -198,24 +198,25 @@ function verifyClearSignedMessage(publicKeys, msg, callback) {
/**
* Generates a new OpenPGP key pair. Currently only supports RSA keys.
* Primary and subkey will be of same type.
* @param {module:enums.publicKey} keyType to indicate what type of key to make.
* @param {module:enums.publicKey} [options.keyType=module:enums.publicKey.rsa_encrypt_sign] to indicate what type of key to make.
* RSA is 1. See {@link http://tools.ietf.org/html/rfc4880#section-9.1}
* @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally)
* @param {String} userId assumes already in form of "User Name <username@email.com>"
* @param {String} passphrase The passphrase used to encrypt the resulting private key
* @param {Integer} options.numBits number of bits for the key creation. (should be 1024+, generally)
* @param {String} options.userId assumes already in form of "User Name <username@email.com>"
* @param {String} options.passphrase The passphrase used to encrypt the resulting private key
* @param {Boolean} [options.unlocked=false] The secret part of the generated key is unlocked
* @param {function} callback (optional) callback(error, result) for async style
* @return {Object} {key: module:key~Key, privateKeyArmored: String, publicKeyArmored: String}
* @static
*/
function generateKeyPair(keyType, numBits, userId, passphrase, callback) {
function generateKeyPair(options, callback) {
if (useWorker(callback)) {
asyncProxy.generateKeyPair(keyType, numBits, userId, passphrase, callback);
asyncProxy.generateKeyPair(options, callback);
return;
}
return execute(function() {
var result = {};
var newKey = key.generate(keyType, numBits, userId, passphrase);
var newKey = key.generate(options);
result.key = newKey;
result.privateKeyArmored = newKey.armor();
result.publicKeyArmored = newKey.toPublic().armor();

View File

@ -182,7 +182,6 @@ SecretKey.prototype.encrypt = function (passphrase) {
blockLen = crypto.cipher[symmetric].blockSize,
iv = crypto.random.getRandomBytes(blockLen);
this.encrypted = '';
this.encrypted += String.fromCharCode(254);
this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric));
@ -255,8 +254,9 @@ SecretKey.prototype.decrypt = function (passphrase) {
'mod';
var parsedMPI = parse_cleartext_mpi(hash, cleartext, this.algorithm);
if (parsedMPI instanceof Error)
if (parsedMPI instanceof Error) {
return false;
}
this.mpi = this.mpi.concat(parsedMPI);
this.isDecrypted = true;
return true;
@ -266,3 +266,11 @@ SecretKey.prototype.generate = function (bits) {
this.mpi = crypto.generateMpi(this.algorithm, bits);
this.isDecrypted = true;
};
/**
* Clear private MPIs, return to initial state
*/
SecretKey.prototype.clearPrivateMPIs = function () {
this.mpi = this.mpi.slice(0, crypto.getPublicMpiCount(this.algorithm));
this.isDecrypted = false;
};

View File

@ -234,13 +234,10 @@ AsyncProxy.prototype.verifyClearSignedMessage = function(publicKeys, message, ca
* @param {String} passphrase The passphrase used to encrypt the resulting private key
* @param {Function} callback receives object with key and public and private armored texts
*/
AsyncProxy.prototype.generateKeyPair = function(keyType, numBits, userId, passphrase, callback) {
AsyncProxy.prototype.generateKeyPair = function(options, callback) {
this.worker.postMessage({
event: 'generate-key-pair',
keyType: keyType,
numBits: numBits,
userId: userId,
passphrase: passphrase
options: options
});
this.tasks.push(function(err, data) {
if (data) {

View File

@ -98,7 +98,7 @@ onmessage = function (event) {
break;
case 'generate-key-pair':
try {
data = window.openpgp.generateKeyPair(msg.keyType, msg.numBits, msg.userId, msg.passphrase);
data = window.openpgp.generateKeyPair(msg.options);
data.key = data.key.toPacketlist();
} catch (e) {
err = e.message;

View File

@ -9,7 +9,7 @@ describe('Basic', function() {
describe("Key generation/encryption/decryption", function() {
var testHelper = function(passphrase, userid, message) {
var key = openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 512, userid, passphrase);
var key = openpgp.generateKeyPair({numBits: 512, userId: userid, passphrase: passphrase});
expect(key).to.exist;
expect(key.key).to.exist;
expect(key.privateKeyArmored).to.exist;
@ -72,7 +72,7 @@ describe('Basic', function() {
var userid = 'Test McTestington <test@example.com>';
var passphrase = 'password';
var key = openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 512, userid, passphrase);
var key = openpgp.generateKeyPair({numBits: 512, userId: userid, passphrase: passphrase});
var info = '\npassphrase: ' + passphrase + '\n' + 'userid: ' + userid + '\n' + 'message: ' + message;

View File

@ -634,7 +634,7 @@ var pgp_desktop_priv =
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zlib, compr.zip]);
expect(key.users[0].selfCertifications[0].features).to.eql(openpgp.config.integrity_protect ? [1] : null); // modification detection
}
var key = openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 512, 'test', 'hello');
var key = openpgp.generateKeyPair({numBits: 512, userId: 'test', passphrase: 'hello'});
testPref(key.key);
testPref(openpgp.key.readArmored(key.publicKeyArmored).keys[0]);
});
@ -653,5 +653,12 @@ var pgp_desktop_priv =
expect(primUser.selfCertificate).to.be.an.instanceof(openpgp.packet.Signature);
});
it('Generated key is not unlocked by default', function() {
var key = openpgp.generateKeyPair({numBits: 512, userId: 'test', passphrase: '123'});
var msg = openpgp.message.fromText('hello').encrypt([key.key]);
msg = msg.decrypt.bind(msg, key.key);
expect(msg).to.throw('Private key is not decrypted.');
});
});

View File

@ -398,7 +398,7 @@ describe('High level API', function() {
describe('Key generation', function() {
it('Generate 1024-bit RSA/RSA key async', function (done) {
openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 1024, 'Test McTestington <test@example.com>', 'hello world', function(err, data) {
openpgp.generateKeyPair({numBits: 1024, userId: 'Test McTestington <test@example.com>', passphrase: 'hello world'}, function(err, data) {
expect(err).to.not.exist;
expect(data).to.exist;
expect(data.publicKeyArmored).to.match(/^-----BEGIN PGP PUBLIC/);
@ -409,7 +409,7 @@ describe('High level API', function() {
});
it('Generate 1024-bit RSA/RSA key sync', function () {
var key = openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 1024, 'Test McTestington <test@example.com>', 'hello world');
var key = openpgp.generateKeyPair({numBits: 1024, userId: 'Test McTestington <test@example.com>', passphrase: 'hello world'});
expect(key).to.exist;
expect(key.publicKeyArmored).to.match(/^-----BEGIN PGP PUBLIC/);
expect(key.privateKeyArmored).to.match(/^-----BEGIN PGP PRIVATE/);