Add decryptKeyPacket to key class. Used to decrypt specific key
packets and replacing the unlock mechanism. Decrypt method of packet_secret_key returns boolean to indicate successful decryption. Add config to util class and cleanup comments. Update tests.
This commit is contained in:
parent
097e602fd0
commit
93376b6e13
File diff suppressed because one or more lines are too long
74
src/key.js
74
src/key.js
|
@ -32,8 +32,6 @@ var config = require('./config');
|
||||||
|
|
||||||
this.packets = packetlist || new packet.list();
|
this.packets = packetlist || new packet.list();
|
||||||
|
|
||||||
this.passphrase = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the primary key packet (secret or public)
|
* Returns the primary key packet (secret or public)
|
||||||
* @returns {packet_secret_key|packet_public_key|null}
|
* @returns {packet_secret_key|packet_public_key|null}
|
||||||
|
@ -87,18 +85,11 @@ var config = require('./config');
|
||||||
return keyIds;
|
return keyIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function findKey(keys, keyIds) {
|
||||||
* Returns first key packet for given array of key IDs
|
|
||||||
* @param {[keyid]} keyIds
|
|
||||||
* @return {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null}
|
|
||||||
*/
|
|
||||||
this.getKeyPacket = function(keyIds) {
|
|
||||||
var keys = this.getAllKeyPackets();
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
var keyId = keys[i].getKeyId();
|
var keyId = keys[i].getKeyId();
|
||||||
for (var j = 0; j < keyIds.length; j++) {
|
for (var j = 0; j < keyIds.length; j++) {
|
||||||
if (keyId.equals(keyIds[j])) {
|
if (keyId.equals(keyIds[j])) {
|
||||||
//TODO return only verified keys
|
|
||||||
return keys[i];
|
return keys[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,28 +97,24 @@ var config = require('./config');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first public key packet for given array of key IDs
|
||||||
|
* @param {[keyid]} keyIds
|
||||||
|
* @return {public_subkey|packet_public_key|null}
|
||||||
|
*/
|
||||||
|
this.getPublicKeyPacket = function(keyIds) {
|
||||||
|
var keys = this.packets.filterByTag(enums.packet.public_key, enums.packet.public_subkey);
|
||||||
|
return findKey(keys, keyIds);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns first private key packet for given array of key IDs
|
* Returns first private key packet for given array of key IDs
|
||||||
* @param {[keyid]} keyIds
|
* @param {[keyid]} keyIds
|
||||||
* @param {Boolean} decrypted decrypt private key packet
|
|
||||||
* @return {secret_subkey|packet_secret_key|null}
|
* @return {secret_subkey|packet_secret_key|null}
|
||||||
*/
|
*/
|
||||||
this.getPrivateKeyPacket = function(keyIds, decrypted) {
|
this.getPrivateKeyPacket = function(keyIds) {
|
||||||
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
||||||
for (var i = 0; i < keys.length; i++) {
|
return findKey(keys, keyIds);
|
||||||
var keyId = keys[i].getKeyId();
|
|
||||||
for (var j = 0; j < keyIds.length; j++) {
|
|
||||||
if (keyId.equals(keyIds[j])) {
|
|
||||||
//TODO return only verified keys
|
|
||||||
if (decrypted) {
|
|
||||||
if (!this.passphrase) throw new Error('No passphrase to decrypt key.');
|
|
||||||
keys[i].decrypt(this.passphrase);
|
|
||||||
}
|
|
||||||
return keys[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -214,27 +201,36 @@ var config = require('./config');
|
||||||
/**
|
/**
|
||||||
* Decrypts all secret key and subkey packets
|
* Decrypts all secret key and subkey packets
|
||||||
* @param {String} passphrase
|
* @param {String} passphrase
|
||||||
* @return {undefined}
|
* @return {Boolean} true if all key and subkey packets decrypted successfully
|
||||||
*/
|
*/
|
||||||
this.decrypt = function(passphrase) {
|
this.decrypt = function(passphrase) {
|
||||||
//TODO return value
|
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
||||||
var keys = this.getAllKeyPackets();
|
for (var i = 0; i < keys.length; i++) {
|
||||||
for (var i in keys) {
|
var success = keys[i].decrypt(passphrase);
|
||||||
if (keys[i].tag == enums.packet.secret_subkey ||
|
if (!success) return false;
|
||||||
keys[i].tag == enums.packet.secret_key) {
|
|
||||||
if (!passphrase && !this.passphrase) throw new Error('No passphrase to decrypt key.');
|
|
||||||
keys[i].decrypt(passphrase || this.passphrase);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlocks the key with passphrase, decryption of secret keys deferred. This allows to decrypt the required private key packets on demand
|
* Decrypts specific key packets by key ID
|
||||||
|
* @param {[keyid]} keyIds
|
||||||
* @param {String} passphrase
|
* @param {String} passphrase
|
||||||
* @return {undefined}
|
* @return {Boolean} true if all key packets decrypted successfully
|
||||||
*/
|
*/
|
||||||
this.unlock = function(passphrase) {
|
this.decryptKeyPacket = function(keyIds, passphrase) {
|
||||||
this.passphrase = passphrase;
|
//TODO return value
|
||||||
|
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var keyId = keys[i].getKeyId();
|
||||||
|
for (var j = 0; j < keyIds.length; j++) {
|
||||||
|
if (keyId.equals(keyIds[j])) {
|
||||||
|
var success = keys[i].decrypt(passphrase);
|
||||||
|
if (!success) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -45,7 +45,7 @@ function message(packetlist) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypt the message
|
* Decrypt the message
|
||||||
* @param {key} privateKey unlocked private key for which the message is encrypted (corresponding to the session key)
|
* @param {key} privateKey private key with decrypted secret data
|
||||||
* @return {[message]} new message with decrypted content
|
* @return {[message]} new message with decrypted content
|
||||||
*/
|
*/
|
||||||
this.decrypt = function(privateKey) {
|
this.decrypt = function(privateKey) {
|
||||||
|
@ -54,7 +54,8 @@ function message(packetlist) {
|
||||||
// nothing to decrypt return unmodified message
|
// nothing to decrypt return unmodified message
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
var privateKeyPacket = privateKey.getPrivateKeyPacket(encryptionKeyIds, true);
|
var privateKeyPacket = privateKey.getPrivateKeyPacket(encryptionKeyIds);
|
||||||
|
if (!privateKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
|
||||||
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
|
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
|
||||||
var pkESKeyPacket;
|
var pkESKeyPacket;
|
||||||
for (var i = 0; i < pkESKeyPacketlist.length; i++) {
|
for (var i = 0; i < pkESKeyPacketlist.length; i++) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ function _openpgp() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decrypts message
|
* decrypts message
|
||||||
* @param {key} privateKey unlocked private key
|
* @param {key} privateKey private key with decrypted secret key data
|
||||||
* @param {message} message the message object with the encrypted data
|
* @param {message} message the message object with the encrypted data
|
||||||
* @return {String|null} decrypted message as as native JavaScript string
|
* @return {String|null} decrypted message as as native JavaScript string
|
||||||
* or null if no literal data found
|
* or null if no literal data found
|
||||||
|
|
|
@ -67,7 +67,7 @@ function packet_secret_key() {
|
||||||
var hash = hashfn(cleartext);
|
var hash = hashfn(cleartext);
|
||||||
|
|
||||||
if (hash != hashtext)
|
if (hash != hashtext)
|
||||||
throw new Error("Hash mismatch.");
|
return new Error("Hash mismatch.");
|
||||||
|
|
||||||
var mpis = crypto.getPrivateMpiCount(algorithm);
|
var mpis = crypto.getPrivateMpiCount(algorithm);
|
||||||
|
|
||||||
|
@ -126,9 +126,10 @@ function packet_secret_key() {
|
||||||
// - Plain or encrypted multiprecision integers comprising the secret
|
// - Plain or encrypted multiprecision integers comprising the secret
|
||||||
// key data. These algorithm-specific fields are as described
|
// key data. These algorithm-specific fields are as described
|
||||||
// below.
|
// below.
|
||||||
|
var parsedMPI = parse_cleartext_mpi('mod', bytes.substr(1), this.algorithm);
|
||||||
this.mpi = this.mpi.concat(parse_cleartext_mpi('mod', bytes.substr(1),
|
if (parsedMPI instanceof Error)
|
||||||
this.algorithm));
|
throw parsedMPI;
|
||||||
|
this.mpi = this.mpi.concat(parsedMPI);
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,11 +201,12 @@ function packet_secret_key() {
|
||||||
*
|
*
|
||||||
* @param {String} str_passphrase The passphrase for this private key
|
* @param {String} str_passphrase The passphrase for this private key
|
||||||
* as string
|
* as string
|
||||||
* @return {Boolean} True if the passphrase was correct; false if not
|
* @return {Boolean} True if the passphrase was correct or MPI already
|
||||||
|
* decrypted; false if not
|
||||||
*/
|
*/
|
||||||
this.decrypt = function(passphrase) {
|
this.decrypt = function(passphrase) {
|
||||||
if (this.isDecrypted)
|
if (this.isDecrypted)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
var i = 0,
|
var i = 0,
|
||||||
symmetric,
|
symmetric,
|
||||||
|
@ -249,10 +251,12 @@ function packet_secret_key() {
|
||||||
'sha1' :
|
'sha1' :
|
||||||
'mod';
|
'mod';
|
||||||
|
|
||||||
|
var parsedMPI = parse_cleartext_mpi(hash, cleartext, this.algorithm);
|
||||||
this.mpi = this.mpi.concat(parse_cleartext_mpi(hash, cleartext,
|
if (parsedMPI instanceof Error)
|
||||||
this.algorithm));
|
return false;
|
||||||
|
this.mpi = this.mpi.concat(parsedMPI);
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.generate = function(bits, passphrase) {
|
this.generate = function(bits, passphrase) {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
var config = require('../config');
|
||||||
|
|
||||||
var Util = function() {
|
var Util = function() {
|
||||||
|
|
||||||
this.readNumber = function(bytes) {
|
this.readNumber = function(bytes) {
|
||||||
|
@ -221,16 +223,11 @@ var Util = function() {
|
||||||
/**
|
/**
|
||||||
* Helper function to print a debug message. Debug
|
* Helper function to print a debug message. Debug
|
||||||
* messages are only printed if
|
* messages are only printed if
|
||||||
* openpgp.config.debug is set to true. The calling
|
* openpgp.config.debug is set to true.
|
||||||
* Javascript context MUST define
|
|
||||||
* a "showMessages(text)" function. Line feeds ('\n')
|
|
||||||
* are automatically converted to HTML line feeds '<br/>'
|
|
||||||
* @param {String} str String of the debug message
|
* @param {String} str String of the debug message
|
||||||
* @return {String} An HTML tt entity containing a paragraph with a
|
|
||||||
* style attribute where the debug message is HTMLencoded in.
|
|
||||||
*/
|
*/
|
||||||
this.print_debug = function(str) {
|
this.print_debug = function(str) {
|
||||||
if (this.debug) {
|
if (config.debug) {
|
||||||
console.log(str);
|
console.log(str);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -238,17 +235,12 @@ var Util = function() {
|
||||||
/**
|
/**
|
||||||
* Helper function to print a debug message. Debug
|
* Helper function to print a debug message. Debug
|
||||||
* messages are only printed if
|
* messages are only printed if
|
||||||
* openpgp.config.debug is set to true. The calling
|
* openpgp.config.debug is set to true.
|
||||||
* Javascript context MUST define
|
|
||||||
* a "showMessages(text)" function. Line feeds ('\n')
|
|
||||||
* are automatically converted to HTML line feeds '<br/>'
|
|
||||||
* Different than print_debug because will call hexstrdump iff necessary.
|
* Different than print_debug because will call hexstrdump iff necessary.
|
||||||
* @param {String} str String of the debug message
|
* @param {String} str String of the debug message
|
||||||
* @return {String} An HTML tt entity containing a paragraph with a
|
|
||||||
* style attribute where the debug message is HTMLencoded in.
|
|
||||||
*/
|
*/
|
||||||
this.print_debug_hexstr_dump = function(str, strToHex) {
|
this.print_debug_hexstr_dump = function(str, strToHex) {
|
||||||
if (this.debug) {
|
if (config.debug) {
|
||||||
str = str + this.hexstrdump(strToHex);
|
str = str + this.hexstrdump(strToHex);
|
||||||
console.log(str);
|
console.log(str);
|
||||||
}
|
}
|
||||||
|
@ -256,30 +248,20 @@ var Util = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to print an error message.
|
* Helper function to print an error message.
|
||||||
* The calling Javascript context MUST define
|
|
||||||
* a "showMessages(text)" function. Line feeds ('\n')
|
|
||||||
* are automatically converted to HTML line feeds '<br/>'
|
|
||||||
* @param {String} str String of the error message
|
* @param {String} str String of the error message
|
||||||
* @return {String} A HTML paragraph entity with a style attribute
|
|
||||||
* containing the HTML encoded error message
|
|
||||||
*/
|
*/
|
||||||
this.print_error = function(str) {
|
this.print_error = function(str) {
|
||||||
if (this.debug)
|
if (config.debug)
|
||||||
throw str;
|
throw str;
|
||||||
console.log(str);
|
console.log(str);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to print an info message.
|
* Helper function to print an info message.
|
||||||
* The calling Javascript context MUST define
|
|
||||||
* a "showMessages(text)" function. Line feeds ('\n')
|
|
||||||
* are automatically converted to HTML line feeds '<br/>'.
|
|
||||||
* @param {String} str String of the info message
|
* @param {String} str String of the info message
|
||||||
* @return {String} A HTML paragraph entity with a style attribute
|
|
||||||
* containing the HTML encoded info message
|
|
||||||
*/
|
*/
|
||||||
this.print_info = function(str) {
|
this.print_info = function(str) {
|
||||||
if (this.debug)
|
if (config.debug)
|
||||||
console.log(str);
|
console.log(str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ unit.register("Key generation/encryption/decryption", function() {
|
||||||
|
|
||||||
var msg = openpgp.message.readArmored(encrypted);
|
var msg = openpgp.message.readArmored(encrypted);
|
||||||
|
|
||||||
privKey.unlock(passphrase);
|
var keyids = msg.getEncryptionKeyIds();
|
||||||
|
|
||||||
|
privKey.decryptKeyPacket(keyids, passphrase);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var decrypted = openpgp.decryptMessage(privKey, msg);
|
var decrypted = openpgp.decryptMessage(privKey, msg);
|
||||||
|
@ -34,7 +36,7 @@ unit.register("Key generation/encryption/decryption", function() {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
unit.register("Encryption/decryption", function() {
|
unit.register("Message encryption/decryption", function() {
|
||||||
var openpgp = require('../../');
|
var openpgp = require('../../');
|
||||||
|
|
||||||
var result = [];
|
var result = [];
|
||||||
|
@ -117,11 +119,29 @@ unit.register("Encryption/decryption", function() {
|
||||||
|
|
||||||
var privKey = openpgp.key.readArmored(priv_key);
|
var privKey = openpgp.key.readArmored(priv_key);
|
||||||
|
|
||||||
privKey.unlock('hello world');
|
// get key IDs the message is encrypted for
|
||||||
|
var keyids = message.getEncryptionKeyIds();
|
||||||
|
|
||||||
var decrypted = openpgp.decryptMessage(privKey, message);
|
// decrypt only required key packets
|
||||||
|
var success = privKey.decryptKeyPacket(keyids, 'hello what?')
|
||||||
|
|
||||||
result[0] = new unit.result('Encrypt plain text and afterwards decrypt leads to same result', plaintext == decrypted);
|
result.push(new unit.result('Decrypting key packet with wrong password returns false', !success));
|
||||||
|
|
||||||
|
var decrypted, error;
|
||||||
|
try {
|
||||||
|
decrypted = openpgp.decryptMessage(privKey, message);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
result.push(new unit.result('Calling decryptMessage with not encrypted key packet leads to exception: \'' + (error || '') + '\'', error));
|
||||||
|
|
||||||
|
success = privKey.decryptKeyPacket(keyids, 'hello world');
|
||||||
|
|
||||||
|
result.push(new unit.result('Decrypting key packet with correct password returns true', success));
|
||||||
|
|
||||||
|
decrypted = openpgp.decryptMessage(privKey, message);
|
||||||
|
|
||||||
|
result.push(new unit.result('Encrypt plain text and afterwards decrypt leads to same result', plaintext == decrypted));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user