
Rename resources to dist. Eliminate keyring bundle and expose keyring class in openpgp module. Add mochaTest grunt task to run node server-side tests. Add node_pack grunt task to create npm package into dist and install it for testing. Add node_store config property which specifies location of localStorage emulation when using node. Add repository info to package.json. Move util.js to src directory from util since it is the only file there. Rename class properties in openpgp to the new class names.
367 lines
18 KiB
HTML
367 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>JSDoc: Source: message.js</title>
|
|
|
|
<script src="scripts/prettify/prettify.js"> </script>
|
|
<script src="scripts/prettify/lang-css.js"> </script>
|
|
<!--[if lt IE 9]>
|
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
<![endif]-->
|
|
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
|
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="main">
|
|
|
|
<h1 class="page-title">Source: message.js</h1>
|
|
|
|
|
|
|
|
|
|
|
|
<section>
|
|
<article>
|
|
<pre class="prettyprint source"><code>// GPG4Browsers - An OpenPGP implementation in javascript
|
|
// Copyright (C) 2011 Recurity Labs GmbH
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 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
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
/**
|
|
* @requires config
|
|
* @requires crypto
|
|
* @requires encoding/armor
|
|
* @requires enums
|
|
* @requires packet
|
|
* @module message
|
|
*/
|
|
|
|
var packet = require('./packet'),
|
|
enums = require('./enums.js'),
|
|
armor = require('./encoding/armor.js'),
|
|
config = require('./config'),
|
|
crypto = require('./crypto');
|
|
|
|
/**
|
|
* @class
|
|
* @classdesc Class that represents an OpenPGP message.
|
|
* Can be an encrypted message, signed message, compressed message or literal message
|
|
* @param {module:packet/packetlist} packetlist The packets that form this message
|
|
* See {@link http://tools.ietf.org/html/rfc4880#section-11.3}
|
|
*/
|
|
|
|
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 {Array<module:type/keyid>} array of keyid objects
|
|
*/
|
|
Message.prototype.getEncryptionKeyIds = function() {
|
|
var keyIds = [];
|
|
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey);
|
|
pkESKeyPacketlist.forEach(function(packet) {
|
|
keyIds.push(packet.publicKeyId);
|
|
});
|
|
return keyIds;
|
|
};
|
|
|
|
/**
|
|
* Returns the key IDs of the keys that signed the message
|
|
* @return {Array<module:type/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.onePassSignature);
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* Decrypt the message
|
|
* @param {module:key~Key} privateKey private key with decrypted secret data
|
|
* @return {Array<module:message~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.publicKeyEncryptedSessionKey);
|
|
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.symmetricallyEncrypted, enums.packet.symEncryptedIntegrityProtected);
|
|
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) {
|
|
return literal.getText();
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Encrypt the message
|
|
* @param {Array<module:key~Key>} keys array of keys, used to encrypt the message
|
|
* @return {Array<module:message~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.PublicKeyEncryptedSessionKey();
|
|
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);
|
|
} else {
|
|
throw new Error('Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex());
|
|
}
|
|
});
|
|
var symEncryptedPacket;
|
|
if (config.integrity_protect) {
|
|
symEncryptedPacket = new packet.SymEncryptedIntegrityProtected();
|
|
} else {
|
|
symEncryptedPacket = new packet.SymmetricallyEncrypted();
|
|
}
|
|
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 {Array<module:key~Key>} privateKey private keys with decrypted secret key data for signing
|
|
* @return {module:message~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;
|
|
var i;
|
|
for (i = 0; i < privateKeys.length; i++) {
|
|
var onePassSig = new packet.OnePassSignature();
|
|
onePassSig.type = signatureType;
|
|
//TODO get preferred hashg algo from key signature
|
|
onePassSig.hashAlgorithm = config.prefer_hash_algorithm;
|
|
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
|
|
if (!signingKeyPacket) {
|
|
throw new Error('Could not find valid key packet for signing in key ' + privateKeys[i].primaryKey.getKeyId().toHex());
|
|
}
|
|
onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
|
onePassSig.signingKeyId = signingKeyPacket.getKeyId();
|
|
packetlist.push(onePassSig);
|
|
}
|
|
|
|
packetlist.push(literalDataPacket);
|
|
|
|
for (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 {Array<module:key~Key>} publicKeys public keys to verify signatures
|
|
* @return {Array<({keyid: module:type/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.valid = signatureList[i].verify(publicKeyPacket, literalDataList[0]);
|
|
result.push(verifiedSig);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Unwrap compressed message
|
|
* @return {module:message~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;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 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 {module:message~Message} new message object
|
|
* @static
|
|
*/
|
|
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);
|
|
return newMessage;
|
|
}
|
|
|
|
/**
|
|
* creates new message object from text
|
|
* @param {String} text
|
|
* @return {module:message~Message} new message object
|
|
* @static
|
|
*/
|
|
function fromText(text) {
|
|
var literalDataPacket = new packet.Literal();
|
|
// text will be converted to UTF8
|
|
literalDataPacket.setText(text);
|
|
var literalDataPacketlist = new packet.List();
|
|
literalDataPacketlist.push(literalDataPacket);
|
|
var newMessage = new Message(literalDataPacketlist);
|
|
return newMessage;
|
|
}
|
|
|
|
/**
|
|
* creates new message object from binary data
|
|
* @param {String} bytes
|
|
* @return {module:message~Message} new message object
|
|
* @static
|
|
*/
|
|
function fromBinary(bytes) {
|
|
var literalDataPacket = new packet.Literal();
|
|
literalDataPacket.setBytes(bytes, enums.read(enums.literal, enums.literal.binary));
|
|
var literalDataPacketlist = new packet.List();
|
|
literalDataPacketlist.push(literalDataPacket);
|
|
var newMessage = new Message(literalDataPacketlist);
|
|
return newMessage;
|
|
}
|
|
|
|
exports.Message = Message;
|
|
exports.readArmored = readArmored;
|
|
exports.fromText = fromText;
|
|
exports.fromBinary = fromBinary;
|
|
</code></pre>
|
|
</article>
|
|
</section>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<nav>
|
|
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="module-cleartext.html">cleartext</a></li><li><a href="module-config.html">config</a></li><li><a href="config.html">config/config</a></li><li><a href="localStorage.html">config/localStorage</a></li><li><a href="module-crypto.html">crypto</a></li><li><a href="cfb.html">crypto/cfb</a></li><li><a href="cipher.html">crypto/cipher</a></li><li><a href="aes.html">crypto/cipher/aes</a></li><li><a href="blowfish.html">crypto/cipher/blowfish</a></li><li><a href="cast5.html">crypto/cipher/cast5</a></li><li><a href="des.html">crypto/cipher/des</a></li><li><a href="twofish.html">crypto/cipher/twofish</a></li><li><a href="crypto.html">crypto/crypto</a></li><li><a href="hash.html">crypto/hash</a></li><li><a href="md5.html">crypto/hash/md5</a></li><li><a href="ripe-md.html">crypto/hash/ripe-md</a></li><li><a href="sha.html">crypto/hash/sha</a></li><li><a href="pkcs1.html">crypto/pkcs1</a></li><li><a href="public_key.html">crypto/public_key</a></li><li><a href="dsa.html">crypto/public_key/dsa</a></li><li><a href="elgamal.html">crypto/public_key/elgamal</a></li><li><a href="jsbn.html">crypto/public_key/jsbn</a></li><li><a href="rsa.html">crypto/public_key/rsa</a></li><li><a href="random.html">crypto/random</a></li><li><a href="signature.html">crypto/signature</a></li><li><a href="armor.html">encoding/armor</a></li><li><a href="base64.html">encoding/base64</a></li><li><a href="module-enums.html">enums</a></li><li><a href="module-key.html">key</a></li><li><a href="module-keyring.html">keyring</a></li><li><a href="keyring.html">keyring/keyring</a></li><li><a href="localstore.html">keyring/localstore</a></li><li><a href="module-message.html">message</a></li><li><a href="module-openpgp.html">openpgp</a></li><li><a href="module-packet.html">packet</a></li><li><a href="compressed.html">packet/compressed</a></li><li><a href="literal.html">packet/literal</a></li><li><a href="marker.html">packet/marker</a></li><li><a href="one_pass_signature.html">packet/one_pass_signature</a></li><li><a href="packet.html">packet/packet</a></li><li><a href="packetlist.html">packet/packetlist</a></li><li><a href="public_key_.html">packet/public_key</a></li><li><a href="public_key_encrypted_session_key.html">packet/public_key_encrypted_session_key</a></li><li><a href="public_subkey.html">packet/public_subkey</a></li><li><a href="secret_key.html">packet/secret_key</a></li><li><a href="secret_subkey.html">packet/secret_subkey</a></li><li><a href="signature_.html">packet/signature</a></li><li><a href="sym_encrypted_integrity_protected.html">packet/sym_encrypted_integrity_protected</a></li><li><a href="sym_encrypted_session_key.html">packet/sym_encrypted_session_key</a></li><li><a href="symmetrically_encrypted.html">packet/symmetrically_encrypted</a></li><li><a href="trust.html">packet/trust</a></li><li><a href="user_attribute.html">packet/user_attribute</a></li><li><a href="userid.html">packet/userid</a></li><li><a href="keyid.html">type/keyid</a></li><li><a href="mpi.html">type/mpi</a></li><li><a href="s2k.html">type/s2k</a></li><li><a href="module-util.html">util</a></li></ul><h3>Classes</h3><ul><li><a href="JXG.Util.html">JXG.Util</a></li><li><a href="module-cleartext-CleartextMessage.html">cleartext~CleartextMessage</a></li><li><a href="localStorage-LocalStorage.html">config/localStorage~LocalStorage</a></li><li><a href="keyring-Keyring.html">keyring/keyring~Keyring</a></li><li><a href="module-key-Key.html">key~Key</a></li><li><a href="module-key-SubKey.html">key~SubKey</a></li><li><a href="module-key-User.html">key~User</a></li><li><a href="module-message-Message.html">message~Message</a></li><li><a href="compressed-Compressed.html">packet/compressed~Compressed</a></li><li><a href="literal-Literal.html">packet/literal~Literal</a></li><li><a href="marker-Marker.html">packet/marker~Marker</a></li><li><a href="one_pass_signature-OnePassSignature.html">packet/one_pass_signature~OnePassSignature</a></li><li><a href="packetlist-Packetlist.html">packet/packetlist~Packetlist</a></li><li><a href="public_key_encrypted_session_key-PublicKeyEncryptedSessionKey.html">packet/public_key_encrypted_session_key~PublicKeyEncryptedSessionKey</a></li><li><a href="public_key-PublicKey.html">packet/public_key~PublicKey</a></li><li><a href="public_subkey-PublicSubkey.html">packet/public_subkey~PublicSubkey</a></li><li><a href="secret_key-SecretKey.html">packet/secret_key~SecretKey</a></li><li><a href="secret_subkey-SecretSubkey.html">packet/secret_subkey~SecretSubkey</a></li><li><a href="signature-Signature.html">packet/signature~Signature</a></li><li><a href="sym_encrypted_integrity_protected-SymEncryptedIntegrityProtected.html">packet/sym_encrypted_integrity_protected~SymEncryptedIntegrityProtected</a></li><li><a href="sym_encrypted_session_key-SymEncryptedSessionKey.html">packet/sym_encrypted_session_key~SymEncryptedSessionKey</a></li><li><a href="symmetrically_encrypted-SymmetricallyEncrypted.html">packet/symmetrically_encrypted~SymmetricallyEncrypted</a></li><li><a href="trust-Trust.html">packet/trust~Trust</a></li><li><a href="user_attribute-UserAttribute.html">packet/user_attribute~UserAttribute</a></li><li><a href="userid-Userid.html">packet/userid~Userid</a></li><li><a href="keyid-Keyid.html">type/keyid~Keyid</a></li><li><a href="mpi-MPI.html">type/mpi~MPI</a></li><li><a href="s2k-S2K.html">type/s2k~S2K</a></li></ul>
|
|
</nav>
|
|
|
|
<br clear="both">
|
|
|
|
<footer>
|
|
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Thu Jan 09 2014 02:24:28 GMT-0800 (PST)
|
|
</footer>
|
|
|
|
<script> prettyPrint(); </script>
|
|
<script src="scripts/linenumber.js"> </script>
|
|
</body>
|
|
</html>
|