Move methods of Key and Message class to prototype. Clean up openpgp.js file.

This commit is contained in:
Thomas Oberndörfer 2013-12-02 14:54:05 +01:00
parent 89eb5dff2a
commit be96de5188
5 changed files with 1858 additions and 2419 deletions

File diff suppressed because one or more lines are too long

View File

@ -22,272 +22,274 @@ var config = require('./config');
/**
* @class
* @classdesc Class that represents an OpenPGP key. Must contain a master key.
* @param {packetlist} packetlist [description]
* Can contain additional subkeys, signatures,
* user ids, user attributes.
* @classdesc Class that represents an OpenPGP key. Must contain a primary key.
* Can contain additional subkeys, signatures, user ids, user attributes.
* @param {packetlist} packetlist The packets that form this key
*/
function key(packetlist) {
function Key(packetlist) {
if (!(this instanceof Key)) {
return new Key(packetlist);
}
this.packets = packetlist || new packet.list();
}
/**
* Returns the primary key packet (secret or public)
* @returns {packet_secret_key|packet_public_key|null}
*/
this.getKeyPacket = function() {
for (var i = 0; i < this.packets.length; i++) {
if (this.packets[i].tag == enums.packet.public_key ||
this.packets[i].tag == enums.packet.secret_key) {
return this.packets[i];
}
/**
* Returns the primary key packet (secret or public)
* @returns {packet_secret_key|packet_public_key|null}
*/
Key.prototype.getKeyPacket = function() {
for (var i = 0; i < this.packets.length; i++) {
if (this.packets[i].tag == enums.packet.public_key ||
this.packets[i].tag == enums.packet.secret_key) {
return this.packets[i];
}
return null;
}
return null;
};
/**
* Returns all the private and public subkey packets
* @returns {[public_subkey|secret_subkey]}
*/
this.getSubkeyPackets = function() {
/**
* Returns all the private and public subkey packets
* @returns {[public_subkey|secret_subkey]}
*/
Key.prototype.getSubkeyPackets = function() {
var subkeys = [];
var subkeys = [];
for (var i = 0; i < this.packets.length; i++) {
if (this.packets[i].tag == enums.packet.public_subkey ||
this.packets[i].tag == enums.packet.secret_subkey) {
subkeys.push(this.packets[i]);
}
for (var i = 0; i < this.packets.length; i++) {
if (this.packets[i].tag == enums.packet.public_subkey ||
this.packets[i].tag == enums.packet.secret_subkey) {
subkeys.push(this.packets[i]);
}
return subkeys;
}
/**
* Returns all the private and public key and subkey packets
* @returns {[public_subkey|secret_subkey|packet_secret_key|packet_public_key]}
*/
this.getAllKeyPackets = function() {
return [this.getKeyPacket()].concat(this.getSubkeyPackets());
return subkeys;
};
/**
* Returns all the private and public key and subkey packets
* @returns {[public_subkey|secret_subkey|packet_secret_key|packet_public_key]}
*/
Key.prototype.getAllKeyPackets = function() {
return [this.getKeyPacket()].concat(this.getSubkeyPackets());
};
/**
* Returns key IDs of all key packets
* @returns {[keyid]}
*/
Key.prototype.getKeyIds = function() {
var keyIds = [];
var keys = this.getAllKeyPackets();
for (var i = 0; i < keys.length; i++) {
keyIds.push(keys[i].getKeyId());
}
return keyIds;
};
/**
* Returns key IDs of all key packets
* @returns {[keyid]}
*/
this.getKeyIds = function() {
var keyIds = [];
var keys = this.getAllKeyPackets();
for (var i = 0; i < keys.length; i++) {
keyIds.push(keys[i].getKeyId());
}
return keyIds;
}
function findKey(keys, keyIds) {
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])) {
return keys[i];
}
}
}
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
* @param {[keyid]} keyIds
* @return {secret_subkey|packet_secret_key|null}
*/
this.getPrivateKeyPacket = function(keyIds) {
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
return findKey(keys, keyIds);
}
/**
* Returns true if this is a public key
* @return {Boolean}
*/
this.isPublic = function() {
var publicKeyPackets = this.packets.filterByTag(enums.packet.public_key);
return publicKeyPackets.length ? true : false;
}
/**
* Returns true if this is a private key
* @return {Boolean}
*/
this.isPrivate = function() {
var privateKeyPackets = this.packets.filterByTag(enums.packet.private_key);
return privateKeyPackets.length ? true : false;
}
/**
* Returns key as public key
* @return {key} public key
*/
this.toPublic = function() {
for (var i = 0; i < this.packets.length; i++) {
if (this.packets[i].tag == enums.packet.secret_key) {
var bytes = this.packets[i].writePublicKey();
var pubKeyPacket = new packet.public_key();
pubKeyPacket.read(bytes);
this.packets[i] = pubKeyPacket;
}
if (this.packets[i].tag == enums.packet.secret_subkey) {
var bytes = this.packets[i].writePublicKey();
var pubSubkeyPacket = new packet.public_subkey();
pubSubkeyPacket.read(bytes);
this.packets[i] = pubSubkeyPacket;
}
}
return this;
}
/**
* Returns ASCII armored text of key
* @return {String} ASCII armor
*/
this.armor = function() {
var type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
return armor.encode(type, this.packets.write());
}
/**
* Returns first key packet that is available for signing
* @return {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null}
*/
this.getSigningKeyPacket = function() {
var signing = [ enums.publicKey.rsa_encrypt_sign, enums.publicKey.rsa_sign, enums.publicKey.dsa];
signing = signing.map(function(s) {
return enums.read(enums.publicKey, s);
});
var keys = this.getAllKeyPackets();
for (var i = 0; i < keys.length; i++) {
if (signing.indexOf(keys[i].algorithm) !== -1) {
function findKey(keys, keyIds) {
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])) {
return keys[i];
}
}
return null;
}
/**
* Returns preferred signature hash algorithm of this key
* @return {String}
*/
function getPreferredSignatureHashAlgorithm() {
//TODO implement: https://tools.ietf.org/html/rfc4880#section-5.2.3.8
//separate private key preference from digest preferences
return config.prefer_hash_algorithm;
}
/**
* Returns the first valid encryption key packet for this key
* @returns {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null} key packet or null if no encryption key has been found
*/
this.getEncryptionKeyPacket = function() {
// V4: by convention subkeys are prefered for encryption service
// V3: keys MUST NOT have subkeys
var isValidEncryptionKey = function(key) {
//TODO evaluate key flags: http://tools.ietf.org/html/rfc4880#section-5.2.3.21
return key.algorithm != enums.read(enums.publicKey, enums.publicKey.dsa) && key.algorithm != enums.read(enums.publicKey,
enums.publicKey.rsa_sign);
//TODO verify key
//&& keys.verifyKey()
};
var subkeys = this.getSubkeyPackets();
for (var j = 0; j < subkeys.length; j++) {
if (isValidEncryptionKey(subkeys[j])) {
return subkeys[j];
}
}
// if no valid subkey for encryption, use primary key
var primaryKey = this.getKeyPacket();
if (isValidEncryptionKey(primaryKey)) {
return primaryKey;
}
return null;
}
/**
* Decrypts all secret key and subkey packets
* @param {String} passphrase
* @return {Boolean} true if all key and subkey packets decrypted successfully
*/
this.decrypt = function(passphrase) {
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
for (var i = 0; i < keys.length; i++) {
var success = keys[i].decrypt(passphrase);
if (!success) return false;
}
return true;
}
/**
* Decrypts specific key packets by key ID
* @param {[keyid]} keyIds
* @param {String} passphrase
* @return {Boolean} true if all key packets decrypted successfully
*/
this.decryptKeyPacket = function(keyIds, 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
this.verify = function() {
}
// TODO
this.revoke = function() {
}
return null;
}
/**
* Returns first public key packet for given array of key IDs
* @param {[keyid]} keyIds
* @return {public_subkey|packet_public_key|null}
*/
Key.prototype.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
* @param {[keyid]} keyIds
* @return {secret_subkey|packet_secret_key|null}
*/
Key.prototype.getPrivateKeyPacket = function(keyIds) {
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
return findKey(keys, keyIds);
};
/**
* Returns true if this is a public key
* @return {Boolean}
*/
Key.prototype.isPublic = function() {
var publicKeyPackets = this.packets.filterByTag(enums.packet.public_key);
return publicKeyPackets.length ? true : false;
};
/**
* Returns true if this is a private key
* @return {Boolean}
*/
Key.prototype.isPrivate = function() {
var privateKeyPackets = this.packets.filterByTag(enums.packet.private_key);
return privateKeyPackets.length ? true : false;
};
/**
* Returns key as public key
* @return {key} public key
*/
Key.prototype.toPublic = function() {
for (var i = 0; i < this.packets.length; i++) {
if (this.packets[i].tag == enums.packet.secret_key) {
var bytes = this.packets[i].writePublicKey();
var pubKeyPacket = new packet.public_key();
pubKeyPacket.read(bytes);
this.packets[i] = pubKeyPacket;
}
if (this.packets[i].tag == enums.packet.secret_subkey) {
var bytes = this.packets[i].writePublicKey();
var pubSubkeyPacket = new packet.public_subkey();
pubSubkeyPacket.read(bytes);
this.packets[i] = pubSubkeyPacket;
}
}
return this;
};
/**
* Returns ASCII armored text of key
* @return {String} ASCII armor
*/
Key.prototype.armor = function() {
var type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
return armor.encode(type, this.packets.write());
};
/**
* Returns first key packet that is available for signing
* @return {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null}
*/
Key.prototype.getSigningKeyPacket = function() {
var signing = [ enums.publicKey.rsa_encrypt_sign, enums.publicKey.rsa_sign, enums.publicKey.dsa];
signing = signing.map(function(s) {
return enums.read(enums.publicKey, s);
});
var keys = this.getAllKeyPackets();
for (var i = 0; i < keys.length; i++) {
if (signing.indexOf(keys[i].algorithm) !== -1) {
return keys[i];
}
}
return null;
};
/**
* Returns preferred signature hash algorithm of this key
* @return {String}
*/
Key.prototype.getPreferredSignatureHashAlgorithm = function() {
//TODO implement: https://tools.ietf.org/html/rfc4880#section-5.2.3.8
//separate private key preference from digest preferences
return config.prefer_hash_algorithm;
};
/**
* Returns the first valid encryption key packet for this key
* @returns {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null} key packet or null if no encryption key has been found
*/
Key.prototype.getEncryptionKeyPacket = function() {
// V4: by convention subkeys are prefered for encryption service
// V3: keys MUST NOT have subkeys
var isValidEncryptionKey = function(key) {
//TODO evaluate key flags: http://tools.ietf.org/html/rfc4880#section-5.2.3.21
return key.algorithm != enums.read(enums.publicKey, enums.publicKey.dsa) && key.algorithm != enums.read(enums.publicKey,
enums.publicKey.rsa_sign);
//TODO verify key
//&& keys.verifyKey()
};
var subkeys = this.getSubkeyPackets();
for (var j = 0; j < subkeys.length; j++) {
if (isValidEncryptionKey(subkeys[j])) {
return subkeys[j];
}
}
// if no valid subkey for encryption, use primary key
var primaryKey = this.getKeyPacket();
if (isValidEncryptionKey(primaryKey)) {
return primaryKey;
}
return null;
};
/**
* Decrypts all secret key and subkey packets
* @param {String} passphrase
* @return {Boolean} true if all key and subkey packets decrypted successfully
*/
Key.prototype.decrypt = function(passphrase) {
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
for (var i = 0; i < keys.length; i++) {
var success = keys[i].decrypt(passphrase);
if (!success) return false;
}
return true;
};
/**
* Decrypts specific key packets by key ID
* @param {[keyid]} keyIds
* @param {String} passphrase
* @return {Boolean} true if all key packets decrypted successfully
*/
Key.prototype.decryptKeyPacket = function(keyIds, 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
Key.prototype.verify = function() {
};
// TODO
Key.prototype.revoke = function() {
};
/**
* reads an OpenPGP armored text and returns a key object
* @param {String} armoredText text to be parsed
* @return {key} new key object
*/
key.readArmored = function(armoredText) {
function readArmored(armoredText) {
//TODO how do we want to handle bad text? Exception throwing
//TODO don't accept non-key armored texts
var input = armor.decode(armoredText).data;
var packetlist = new packet.list();
packetlist.read(input);
var newKey = new key(packetlist);
var newKey = new Key(packetlist);
return newKey;
}
module.exports = key;
exports.Key = Key;
exports.readArmored = readArmored;

View File

@ -24,322 +24,249 @@ var util = require('./util');
/**
* @class
* @classdesc A generic message containing one or more literal packets.
* @classdesc Class that represents an OpenPGP message.
* Can be an encrypted message, signed message, compressed message or literal message
* See http://tools.ietf.org/html/rfc4880#section-11.3
*/
function message(packetlist) {
function Message(packetlist) {
if (!(this instanceof Message)) {
return new Message(packetlist);
}
this.packets = packetlist || new packet.list();
}
/**
* Returns the key IDs of the keys to which the session key is encrypted
* @return {[keyId]} array of keyid objects
*/
this.getEncryptionKeyIds = function() {
var keyIds = [];
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
pkESKeyPacketlist.forEach(function(packet) {
keyIds.push(packet.publicKeyId);
/**
* Returns the key IDs of the keys to which the session key is encrypted
* @return {[keyId]} array of keyid objects
*/
Message.prototype.getEncryptionKeyIds = function() {
var keyIds = [];
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
pkESKeyPacketlist.forEach(function(packet) {
keyIds.push(packet.publicKeyId);
});
return keyIds;
};
/**
* Returns the key IDs of the keys that signed the message
* @return {[keyId]} array of keyid objects
*/
Message.prototype.getSigningKeyIds = function() {
var keyIds = [];
var msg = this.unwrapCompressed();
// search for one pass signatures
var onePassSigList = msg.packets.filterByTag(enums.packet.one_pass_signature);
onePassSigList.forEach(function(packet) {
keyIds.push(packet.signingKeyId);
});
// if nothing found look for signature packets
if (!keyIds.length) {
var signatureList = msg.packets.filterByTag(enums.packet.signature);
signatureList.forEach(function(packet) {
keyIds.push(packet.issuerKeyId);
});
return keyIds;
}
return keyIds;
};
/**
* Decrypt the message
* @param {key} privateKey private key with decrypted secret data
* @return {[message]} new message with decrypted content
*/
Message.prototype.decrypt = function(privateKey) {
var encryptionKeyIds = this.getEncryptionKeyIds();
if (!encryptionKeyIds.length) {
// nothing to decrypt return unmodified message
return this;
}
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 pkESKeyPacket;
for (var i = 0; i < pkESKeyPacketlist.length; i++) {
if (pkESKeyPacketlist[i].publicKeyId.equals(privateKeyPacket.getKeyId())) {
pkESKeyPacket = pkESKeyPacketlist[i];
pkESKeyPacket.decrypt(privateKeyPacket);
break;
}
}
if (pkESKeyPacket) {
var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetrically_encrypted, enums.packet.sym_encrypted_integrity_protected);
if (symEncryptedPacketlist.length !== 0) {
var symEncryptedPacket = symEncryptedPacketlist[0];
symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey);
return new Message(symEncryptedPacket.packets);
}
}
};
/**
* Get literal data that is the body of the message
* @return {String|null} literal body of the message as string
*/
Message.prototype.getLiteralData = function() {
var literal = this.packets.findPacket(enums.packet.literal);
return literal && literal.data || null;
};
/**
* Get literal data as text
* @return {String|null} literal body of the message interpreted as text
*/
Message.prototype.getText = function() {
var literal = this.packets.findPacket(enums.packet.literal);
if (literal) {
var data = literal.data;
if (literal.format == enums.read(enums.literal, enums.literal.binary)
|| literal.format == enums.read(enums.literal, enums.literal.text)) {
// text in a literal packet with format 'binary' or 'text' could be utf8, therefore decode
data = util.decode_utf8(data);
}
return data;
} else {
return null;
}
};
/**
* Encrypt the message
* @param {[key]} keys array of keys, used to encrypt the message
* @return {[message]} new message with encrypted content
*/
Message.prototype.encrypt = function(keys) {
var packetlist = new packet.list();
//TODO get preferred algo from signature
var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher));
keys.forEach(function(key) {
var encryptionKeyPacket = key.getEncryptionKeyPacket();
if (encryptionKeyPacket) {
var pkESKeyPacket = new packet.public_key_encrypted_session_key();
pkESKeyPacket.publicKeyId = encryptionKeyPacket.getKeyId();
pkESKeyPacket.publicKeyAlgorithm = encryptionKeyPacket.algorithm;
pkESKeyPacket.sessionKey = sessionKey;
//TODO get preferred algo from signature
pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher);
pkESKeyPacket.encrypt(encryptionKeyPacket);
packetlist.push(pkESKeyPacket);
}
});
var symEncryptedPacket;
if (config.integrity_protect) {
symEncryptedPacket = new packet.sym_encrypted_integrity_protected();
} else {
symEncryptedPacket = new packet.symmetrically_encrypted();
}
symEncryptedPacket.packets = this.packets;
//TODO get preferred algo from signature
symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey);
packetlist.push(symEncryptedPacket);
return new Message(packetlist);
};
/**
* Sign the message (the literal data packet of the message)
* @param {[key]} privateKey private keys with decrypted secret key data for signing
* @return {message} new message with signed content
*/
Message.prototype.sign = function(privateKeys) {
var packetlist = new packet.list();
var literalDataPacket = this.packets.findPacket(enums.packet.literal);
if (!literalDataPacket) throw new Error('No literal data packet to sign.');
var literalFormat = enums.write(enums.literal, literalDataPacket.format);
var signatureType = literalFormat == enums.literal.binary
? enums.signature.binary : enums.signature.text;
for (var i = 0; i < privateKeys.length; i++) {
var onePassSig = new packet.one_pass_signature();
onePassSig.type = signatureType;
//TODO get preferred hashg algo from key signature
onePassSig.hashAlgorithm = config.prefer_hash_algorithm;
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm;
onePassSig.signingKeyId = signingKeyPacket.getKeyId();
packetlist.push(onePassSig);
}
/**
* Returns the key IDs of the keys that signed the message
* @return {[keyId]} array of keyid objects
*/
this.getSigningKeyIds = function() {
var keyIds = [];
var msg = this.unwrapCompressed();
// search for one pass signatures
var onePassSigList = msg.packets.filterByTag(enums.packet.one_pass_signature);
onePassSigList.forEach(function(packet) {
keyIds.push(packet.signingKeyId);
});
// if nothing found look for signature packets
if (!keyIds.length) {
var signatureList = msg.packets.filterByTag(enums.packet.signature);
signatureList.forEach(function(packet) {
keyIds.push(packet.issuerKeyId);
});
}
return keyIds;
packetlist.push(literalDataPacket);
for (var i = privateKeys.length - 1; i >= 0; i--) {
var signaturePacket = new packet.signature();
signaturePacket.signatureType = signatureType;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
signaturePacket.sign(signingKeyPacket, literalDataPacket);
packetlist.push(signaturePacket);
}
/**
* Decrypt the message
* @param {key} privateKey private key with decrypted secret data
* @return {[message]} new message with decrypted content
*/
this.decrypt = function(privateKey) {
var encryptionKeyIds = this.getEncryptionKeyIds();
if (!encryptionKeyIds.length) {
// nothing to decrypt return unmodified message
return this;
}
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 pkESKeyPacket;
for (var i = 0; i < pkESKeyPacketlist.length; i++) {
if (pkESKeyPacketlist[i].publicKeyId.equals(privateKeyPacket.getKeyId())) {
pkESKeyPacket = pkESKeyPacketlist[i];
pkESKeyPacket.decrypt(privateKeyPacket);
return new Message(packetlist);
};
/**
* Verify message signatures
* @param {[key]} publicKeys public keys to verify signatures
* @return {[{'keyid': keyid, 'valid': Boolean}]} list of signer's keyid and validity of signature
*/
Message.prototype.verify = function(publicKeys) {
var result = [];
var msg = this.unwrapCompressed();
var literalDataList = msg.packets.filterByTag(enums.packet.literal);
if (literalDataList.length !== 1) throw new Error('Can only verify message with one literal data packet.');
var signatureList = msg.packets.filterByTag(enums.packet.signature);
publicKeys.forEach(function(pubKey) {
for (var i = 0; i < signatureList.length; i++) {
var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]);
if (publicKeyPacket) {
var verifiedSig = {};
verifiedSig.keyid = signatureList[i].issuerKeyId;
verifiedSig.status = signatureList[i].verify(publicKeyPacket, literalDataList[0]);
result.push(verifiedSig);
break;
}
}
if (pkESKeyPacket) {
var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetrically_encrypted, enums.packet.sym_encrypted_integrity_protected);
if (symEncryptedPacketlist.length !== 0) {
var symEncryptedPacket = symEncryptedPacketlist[0];
symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey);
return new message(symEncryptedPacket.packets);
}
}
});
return result;
};
/**
* Unwrap compressed message
* @return {message} message Content of compressed message
*/
Message.prototype.unwrapCompressed = function() {
var compressed = this.packets.filterByTag(enums.packet.compressed);
if (compressed.length) {
return new Message(compressed[0].packets);
} else {
return this;
}
};
/**
* Get literal data that is the body of the message
* @return {String|null} literal body of the message as string
*/
this.getLiteralData = function() {
var literal = this.packets.findPacket(enums.packet.literal);
return literal && literal.data || null;
}
/**
* Get literal data as text
* @return {String|null} literal body of the message interpreted as text
*/
this.getText = function() {
var literal = this.packets.findPacket(enums.packet.literal);
if (literal) {
var data = literal.data;
if (literal.format == enums.read(enums.literal, enums.literal.binary)
|| literal.format == enums.read(enums.literal, enums.literal.text)) {
// text in a literal packet with format 'binary' or 'text' could be utf8, therefore decode
data = util.decode_utf8(data);
}
return data;
} else {
return null;
}
}
/**
* Encrypt the message
* @param {[key]} keys array of keys, used to encrypt the message
* @return {[message]} new message with encrypted content
*/
this.encrypt = function(keys) {
var packetlist = new packet.list();
//TODO get preferred algo from signature
var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher));
keys.forEach(function(key) {
var encryptionKeyPacket = key.getEncryptionKeyPacket();
if (encryptionKeyPacket) {
var pkESKeyPacket = new packet.public_key_encrypted_session_key();
pkESKeyPacket.publicKeyId = encryptionKeyPacket.getKeyId();
pkESKeyPacket.publicKeyAlgorithm = encryptionKeyPacket.algorithm;
pkESKeyPacket.sessionKey = sessionKey;
//TODO get preferred algo from signature
pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher);
pkESKeyPacket.encrypt(encryptionKeyPacket);
packetlist.push(pkESKeyPacket);
}
});
var symEncryptedPacket;
if (config.integrity_protect) {
symEncryptedPacket = new packet.sym_encrypted_integrity_protected();
} else {
symEncryptedPacket = new packet.symmetrically_encrypted();
}
symEncryptedPacket.packets = this.packets;
//TODO get preferred algo from signature
symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey);
packetlist.push(symEncryptedPacket);
return new message(packetlist);
}
/**
* Sign the message (the literal data packet of the message)
* @param {[key]} privateKey private keys with decrypted secret key data for signing
* @return {message} new message with signed content
*/
this.sign = function(privateKeys) {
var packetlist = new packet.list();
var literalDataPacket = this.packets.findPacket(enums.packet.literal);
if (!literalDataPacket) throw new Error('No literal data packet to sign.');
var literalFormat = enums.write(enums.literal, literalDataPacket.format);
var signatureType = literalFormat == enums.literal.binary
? enums.signature.binary : enums.signature.text;
for (var i = 0; i < privateKeys.length; i++) {
var onePassSig = new packet.one_pass_signature();
onePassSig.type = signatureType;
//TODO get preferred hashg algo from key signature
onePassSig.hashAlgorithm = config.prefer_hash_algorithm;
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm;
onePassSig.signingKeyId = signingKeyPacket.getKeyId();
packetlist.push(onePassSig);
}
packetlist.push(literalDataPacket);
for (var i = privateKeys.length - 1; i >= 0; i--) {
var signaturePacket = new packet.signature();
signaturePacket.signatureType = signatureType;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
signaturePacket.sign(signingKeyPacket, literalDataPacket);
packetlist.push(signaturePacket);
}
return new message(packetlist);
}
/**
* Verify message signatures
* @param {[key]} publicKeys public keys to verify signatures
* @return {[{'keyid': keyid, 'valid': Boolean}]} list of signer's keyid and validity of signature
*/
this.verify = function(publicKeys) {
var result = [];
var msg = this.unwrapCompressed();
var literalDataList = msg.packets.filterByTag(enums.packet.literal);
if (literalDataList.length !== 1) throw new Error('Can only verify message with one literal data packet.');
var signatureList = msg.packets.filterByTag(enums.packet.signature);
publicKeys.forEach(function(pubKey) {
for (var i = 0; i < signatureList.length; i++) {
var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]);
if (publicKeyPacket) {
var verifiedSig = {};
verifiedSig.keyid = signatureList[i].issuerKeyId;
verifiedSig.status = signatureList[i].verify(publicKeyPacket, literalDataList[0]);
result.push(verifiedSig);
break;
}
}
});
return result;
}
/**
* Unwrap compressed message
* @return {message} message Content of compressed message
*/
this.unwrapCompressed = function() {
var compressed = this.packets.filterByTag(enums.packet.compressed);
if (compressed.length) {
return new message(compressed[0].packets);
} else {
return this;
}
}
/**
* Returns ASCII armored text of message
* @return {String} ASCII armor
*/
this.armor = function() {
return armor.encode(enums.armor.message, this.packets.write());
}
/**
* Decrypts a message and generates user interface message out of the found.
* MDC will be verified as well as message signatures
* @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
* @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
* @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
* @return {String} plaintext of the message or null on error
*/
function decryptAndVerifySignature(private_key, sessionkey, pubkey) {
if (private_key == null || sessionkey == null || sessionkey == "")
return null;
var decrypted = sessionkey.decrypt(this, private_key.keymaterial);
if (decrypted == null)
return null;
var packet;
var position = 0;
var len = decrypted.length;
var validSignatures = new Array();
util.print_debug_hexstr_dump("openpgp.msg.messge decrypt:\n", decrypted);
var messages = openpgp.read_messages_dearmored({
text: decrypted,
openpgp: decrypted
});
for (var m in messages) {
if (messages[m].data) {
this.text = messages[m].data;
}
if (messages[m].signature) {
validSignatures.push(messages[m].verifySignature(pubkey));
}
}
return {
text: this.text,
validSignatures: validSignatures
};
}
/**
* Verifies a message signature. This function can be called after read_message if the message was signed only.
* @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
* @return {boolean} true if the signature was correct; otherwise false
*/
function verifySignature(pubkey) {
var result = false;
if (this.signature.tagType == 2) {
if (!pubkey || pubkey.length == 0) {
var pubkey;
if (this.signature.version == 4) {
pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId);
} else if (this.signature.version == 3) {
pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId);
} else {
util.print_error("unknown signature type on message!");
return false;
}
}
if (pubkey.length == 0)
util.print_warning("Unable to verify signature of issuer: " + util.hexstrdump(this.signature.issuerKeyId) +
". Public key not found in keyring.");
else {
for (var i = 0; i < pubkey.length; i++) {
var tohash = this.text.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n");
if (this.signature.verify(tohash, pubkey[i])) {
util.print_info("Found Good Signature from " + pubkey[i].obj.userIds[0].text + " (0x" + util.hexstrdump(
pubkey[i].obj.getKeyId()).substring(8) + ")");
result = true;
} else {
util.print_error("Signature verification failed: Bad Signature from " + pubkey[i].obj.userIds[0].text +
" (0x" + util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8) + ")");
}
}
}
}
return result;
}
}
/**
* Returns ASCII armored text of message
* @return {String} ASCII armor
*/
Message.prototype.armor = function() {
return armor.encode(enums.armor.message, this.packets.write());
};
/**
* reads an OpenPGP armored message and returns a message object
* @param {String} armoredText text to be parsed
* @return {message} new message object
*/
message.readArmored = function(armoredText) {
function readArmored(armoredText) {
//TODO how do we want to handle bad text? Exception throwing
//TODO don't accept non-message armored texts
var input = armor.decode(armoredText).data;
var packetlist = new packet.list();
packetlist.read(input);
var newMessage = new message(packetlist);
var newMessage = new Message(packetlist);
return newMessage;
}
@ -348,14 +275,16 @@ message.readArmored = function(armoredText) {
* @param {String} text
* @return {message} new message object
*/
message.fromText = function(text) {
function fromText(text) {
var literalDataPacket = new packet.literal();
// text will be converted to UTF8
literalDataPacket.set(text);
var literalDataPacketlist = new packet.list();
literalDataPacketlist.push(literalDataPacket);
var newMessage = new message(literalDataPacketlist);
var newMessage = new Message(literalDataPacketlist);
return newMessage;
}
module.exports = message;
exports.Message = Message;
exports.readArmored = readArmored;
exports.fromText = fromText;

View File

@ -16,296 +16,178 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @fileoverview The openpgp base class should provide all of the functionality
* @fileoverview The openpgp base module should provide all of the functionality
* to consume the openpgp.js library. All additional classes are documented
* for extending and developing on top of the base library.
*/
var armor = require('./encoding/armor.js');
var packet = require('./packet');
var util = require('./util');
var enums = require('./enums.js');
var config = require('./config');
var message = require('./message.js');
/**
* GPG4Browsers Core interface. A single instance is hold
* from the beginning. To use this library call "openpgp.init()"
* @alias openpgp
* @class
* @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library.
* Encrypts message text with keys
* @param {[key]} keys array of keys, used to encrypt the message
* @param {String} text message as native JavaScript string
* @return {String} encrypted ASCII armored message
*/
function _openpgp() {
function encryptMessage(keys, text) {
var msg = message.fromText(text);
msg = msg.encrypt(keys);
var armored = armor.encode(enums.armor.message, msg.packets.write());
return armored;
}
/**
* Encrypts message text with keys
* @param {[key]} keys array of keys, used to encrypt the message
* @param {String} text message as native JavaScript string
* @return {String} encrypted ASCII armored message
*/
function encryptMessage(keys, text) {
var msg = message.fromText(text);
msg = msg.encrypt(keys);
var armored = armor.encode(enums.armor.message, msg.packets.write());
return armored;
/**
* Signs message text and encrypts it
* @param {[key]} publicKeys array of keys, used to encrypt the message
* @param {key} privateKey private key with decrypted secret key data for signing
* @param {String} text message as native JavaScript string
* @return {String} encrypted ASCII armored message
*/
function signAndEncryptMessage(publicKeys, privateKey, text) {
var msg = message.fromText(text);
msg = msg.sign([privateKey]);
msg = msg.encrypt(publicKeys);
var armored = armor.encode(enums.armor.message, msg.packets.write());
return armored;
}
/**
* Decrypts message
* @param {key} privateKey private key with decrypted secret key data
* @param {message} message the message object with the encrypted data
* @return {String|null} decrypted message as as native JavaScript string
* or null if no literal data found
*/
function decryptMessage(privateKey, message) {
message = message.decrypt(privateKey);
return message.getText();
}
/**
* Decrypts message and verifies signatures
* @param {key} privateKey private key with decrypted secret key data
* @param {[key]} publicKeys public keys to verify signatures
* @param {message} message the message object with signed and encrypted data
* @return {{'text': String, signatures: [{'keyid': keyid, 'status': Boolean}]}}
* decrypted message as as native JavaScript string
* with verified signatures or null if no literal data found
*/
function decryptAndVerifyMessage(privateKey, publicKeys, message) {
var result = {};
message = message.decrypt(privateKey);
result.text = message.getText();
if (result.text) {
result.signatures = message.verify(publicKeys);
return result;
}
return null;
}
/**
* Signs message text and encrypts it
* @param {[key]} publicKeys array of keys, used to encrypt the message
* @param {key} privateKey private key with decrypted secret key data for signing
* @param {String} text message as native JavaScript string
* @return {String} encrypted ASCII armored message
*/
function signAndEncryptMessage(publicKeys, privateKey, text) {
var msg = message.fromText(text);
msg = msg.sign([privateKey]);
msg = msg.encrypt(publicKeys);
var armored = armor.encode(enums.armor.message, msg.packets.write());
return armored;
}
/**
* Decrypts message
* @param {key} privateKey private key with decrypted secret key data
* @param {message} message the message object with the encrypted data
* @return {String|null} decrypted message as as native JavaScript string
* or null if no literal data found
*/
function decryptMessage(privateKey, message) {
message = message.decrypt(privateKey);
return message.getText();
}
/**
* Decrypts message and verifies signatures
* @param {key} privateKey private key with decrypted secret key data
* @param {[key]} publicKeys public keys to verify signatures
* @param {message} message the message object with signed and encrypted data
* @return {{'text': String, signatures: [{'keyid': keyid, 'status': Boolean}]}}
* decrypted message as as native JavaScript string
* with verified signatures or null if no literal data found
*/
function decryptAndVerifyMessage(privateKey, publicKeys, message) {
var result = {};
message = message.decrypt(privateKey);
result.text = message.getText();
if (result.text) {
result.signatures = message.verify(publicKeys);
return result;
}
return null;
}
function verifyMessage(publicKeys, messagePacketlist) {
}
function signMessage(privateKey, messagePacketlist) {
}
/**
* TODO: update this doc
* generates a new key pair for openpgp. Beta stage. Currently only
* supports RSA keys, and no subkeys.
* @param {Integer} keyType to indicate what type of key to make.
* RSA is 1. Follows algorithms outlined in OpenPGP.
* @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
* @return {Object} {privateKey: [openpgp_msg_privatekey],
* privateKeyArmored: [string], publicKeyArmored: [string]}
*/
function generateKeyPair(keyType, numBits, userId, passphrase) {
var packetlist = new packet.list();
var secretKeyPacket = new packet.secret_key();
secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType);
secretKeyPacket.generate(numBits);
secretKeyPacket.encrypt(passphrase);
var userIdPacket = new packet.userid();
userIdPacket.read(userId);
var dataToSign = {};
dataToSign.userid = userIdPacket;
dataToSign.key = secretKeyPacket;
var signaturePacket = new packet.signature();
signaturePacket.signatureType = enums.signature.cert_generic;
signaturePacket.publicKeyAlgorithm = keyType;
//TODO we should load preferred hash from config, or as input to this function
signaturePacket.hashAlgorithm = enums.hash.sha256;
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.sign(secretKeyPacket, dataToSign);
var secretSubkeyPacket = new packet.secret_subkey();
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType);
secretSubkeyPacket.generate(numBits);
secretSubkeyPacket.encrypt(passphrase);
dataToSign = {};
dataToSign.key = secretKeyPacket;
dataToSign.bind = secretSubkeyPacket;
var subkeySignaturePacket = new packet.signature();
subkeySignaturePacket.signatureType = enums.signature.subkey_binding;
subkeySignaturePacket.publicKeyAlgorithm = keyType;
//TODO we should load preferred hash from config, or as input to this function
subkeySignaturePacket.hashAlgorithm = enums.hash.sha256;
subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage];
subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
packetlist.push(secretKeyPacket);
packetlist.push(userIdPacket);
packetlist.push(signaturePacket);
packetlist.push(secretSubkeyPacket);
packetlist.push(subkeySignaturePacket);
var armored = armor.encode(enums.armor.private_key, packetlist.write());
return armored;
}
/**
* creates a binary string representation of an encrypted and signed message.
* The message will be encrypted with the public keys specified and signed
* with the specified private key.
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key
* to be used to sign the message
* @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]}
* - public keys to be used to encrypt the message
* @param {String} messagetext message text to encrypt and sign
* @return {String} a binary string representation of the message which
* can be OpenPGP armored
*/
function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) {
var result = "";
var i;
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g, "\n").replace(/\n/g,
"\r\n"));
util.print_debug_hexstr_dump("literal_packet: |" + literal + "|\n", literal);
for (i = 0; i < publickeys.length; i++) {
var onepasssignature = new openpgp_packet_onepasssignature();
var onepasssigstr = "";
if (i === 0)
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
else
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
util.print_debug_hexstr_dump("onepasssigstr: |" + onepasssigstr + "|\n", onepasssigstr);
var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g, "\n").replace(
/\n/g, "\r\n"), privatekey);
util.print_debug_hexstr_dump("datasignature: |" + datasignature.openpgp + "|\n", datasignature.openpgp);
if (i === 0) {
result = onepasssigstr + literal + datasignature.openpgp;
} else {
result = onepasssigstr + result + datasignature.openpgp;
}
}
util.print_debug_hexstr_dump("signed packet: |" + result + "|\n", result);
// signatures done.. now encryption
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
var result2 = "";
// creating session keys for each recipient
for (i = 0; i < publickeys.length; i++) {
var pkey = publickeys[i].getEncryptionKey();
if (pkey === null) {
util.print_error("no encryption key found! Key is for signing only.");
return null;
}
result2 += new openpgp_packet_encryptedsessionkey().
write_pub_key_packet(
pkey.getKeyId(),
pkey.MPIs,
pkey.publicKeyAlgorithm,
openpgp.config.config.encryption_cipher,
sessionkey);
}
if (openpgp.config.config.integrity_protect) {
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher,
sessionkey, result);
} else {
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey,
result);
}
return armor.encode(3, result2, null, null);
}
/**
* creates a binary string representation of an encrypted message.
* The message will be encrypted with the public keys specified
* @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]}
* -public keys to be used to encrypt the message
* @param {String} messagetext message text to encrypt
* @return {String} a binary string representation of the message
* which can be OpenPGP armored
*/
function write_encrypted_message(publickeys, messagetext) {
var result = "";
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g, "\n").replace(/\n/g,
"\r\n"));
util.print_debug_hexstr_dump("literal_packet: |" + literal + "|\n", literal);
result = literal;
// signatures done.. now encryption
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
var result2 = "";
// creating session keys for each recipient
for (var i = 0; i < publickeys.length; i++) {
var pkey = publickeys[i].getEncryptionKey();
if (pkey === null) {
util.print_error("no encryption key found! Key is for signing only.");
return null;
}
result2 += new openpgp_packet_encryptedsessionkey().
write_pub_key_packet(
pkey.getKeyId(),
pkey.MPIs,
pkey.publicKeyAlgorithm,
openpgp.config.config.encryption_cipher,
sessionkey);
}
if (openpgp.config.config.integrity_protect) {
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher,
sessionkey, result);
} else {
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey,
result);
}
return armor.encode(3, result2, null, null);
}
/**
* creates a binary string representation a signed message.
* The message will be signed with the specified private key.
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]}
* - the private key to be used to sign the message
* @param {String} messagetext message text to sign
* @return {Object} {Object: text [String]}, openpgp: {String} a binary
* string representation of the message which can be OpenPGP
* armored(openpgp) and a text representation of the message (text).
* This can be directly used to OpenPGP armor the message
*/
function write_signed_message(privatekey, messagetext) {
var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g, "\n").replace(/\n/,
"\r\n"), privatekey);
var result = {
text: messagetext.replace(/\r\n/g, "\n").replace(/\n/, "\r\n"),
openpgp: sig.openpgp,
hash: sig.hash
};
return armor.encode(2, result, null, null);
}
this.generateKeyPair = generateKeyPair;
this.write_signed_message = write_signed_message;
this.signAndEncryptMessage = signAndEncryptMessage;
this.decryptAndVerifyMessage = decryptAndVerifyMessage
this.encryptMessage = encryptMessage;
this.decryptMessage = decryptMessage;
function signClearMessage(privateKeys, text) {
}
module.exports = new _openpgp();
function verifyClearSignedMessage(publicKeys, message) {
}
/**
* TODO: update this doc
* generates a new key pair for openpgp. Beta stage. Currently only
* supports RSA keys, and no subkeys.
* @param {Integer} keyType to indicate what type of key to make.
* RSA is 1. Follows algorithms outlined in OpenPGP.
* @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
* @return {Object} {privateKey: [openpgp_msg_privatekey],
* privateKeyArmored: [string], publicKeyArmored: [string]}
*/
function generateKeyPair(keyType, numBits, userId, passphrase) {
var packetlist = new packet.list();
var secretKeyPacket = new packet.secret_key();
secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType);
secretKeyPacket.generate(numBits);
secretKeyPacket.encrypt(passphrase);
var userIdPacket = new packet.userid();
userIdPacket.read(userId);
var dataToSign = {};
dataToSign.userid = userIdPacket;
dataToSign.key = secretKeyPacket;
var signaturePacket = new packet.signature();
signaturePacket.signatureType = enums.signature.cert_generic;
signaturePacket.publicKeyAlgorithm = keyType;
//TODO we should load preferred hash from config, or as input to this function
signaturePacket.hashAlgorithm = enums.hash.sha256;
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.sign(secretKeyPacket, dataToSign);
var secretSubkeyPacket = new packet.secret_subkey();
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType);
secretSubkeyPacket.generate(numBits);
secretSubkeyPacket.encrypt(passphrase);
dataToSign = {};
dataToSign.key = secretKeyPacket;
dataToSign.bind = secretSubkeyPacket;
var subkeySignaturePacket = new packet.signature();
subkeySignaturePacket.signatureType = enums.signature.subkey_binding;
subkeySignaturePacket.publicKeyAlgorithm = keyType;
//TODO we should load preferred hash from config, or as input to this function
subkeySignaturePacket.hashAlgorithm = enums.hash.sha256;
subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage];
subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
packetlist.push(secretKeyPacket);
packetlist.push(userIdPacket);
packetlist.push(signaturePacket);
packetlist.push(secretSubkeyPacket);
packetlist.push(subkeySignaturePacket);
var armored = armor.encode(enums.armor.private_key, packetlist.write());
return armored;
}
/**
* creates a binary string representation a signed message.
* The message will be signed with the specified private key.
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]}
* - the private key to be used to sign the message
* @param {String} messagetext message text to sign
* @return {Object} {Object: text [String]}, openpgp: {String} a binary
* string representation of the message which can be OpenPGP
* armored(openpgp) and a text representation of the message (text).
* This can be directly used to OpenPGP armor the message
*/
/*
function write_signed_message(privatekey, messagetext) {
var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g, "\n").replace(/\n/,
"\r\n"), privatekey);
var result = {
text: messagetext.replace(/\r\n/g, "\n").replace(/\n/, "\r\n"),
openpgp: sig.openpgp,
hash: sig.hash
};
return armor.encode(2, result, null, null);
}
*/
exports.encryptMessage = encryptMessage;
exports.signAndEncryptMessage = signAndEncryptMessage;
exports.decryptMessage = decryptMessage;
exports.decryptAndVerifyMessage = decryptAndVerifyMessage
exports.signClearMessage = signClearMessage;
exports.verifyClearSignedMessage = verifyClearSignedMessage;
exports.generateKeyPair = generateKeyPair;

File diff suppressed because one or more lines are too long