diff --git a/src/crypto/random.js b/src/crypto/random.js index 6f4b551d..9c85ca5f 100644 --- a/src/crypto/random.js +++ b/src/crypto/random.js @@ -24,6 +24,8 @@ var type_mpi = require('../type/mpi.js'); var nodeCrypto = null; +var randomBuffer = null; +var randomBufferIndex = 0; if (typeof window === 'undefined') { nodeCrypto = require('crypto'); @@ -79,11 +81,20 @@ module.exports = { * @param {Uint32Array} buf */ getRandomValues: function(buf) { - if (nodeCrypto === null) { + if (typeof window !== 'undefined' && window.crypto) { window.crypto.getRandomValues(buf); - } else { + } else if (nodeCrypto) { var bytes = nodeCrypto.randomBytes(4); buf[0] = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; + } else if (randomBuffer) { + if (randomBufferIndex < buf.length) { + throw new Error('Random number buffer depleted.') + } + for (var i = 0; i < buf.length; i++) { + buf[i] = randomBuffer[--randomBufferIndex]; + } + } else { + throw new Error('No secure random number generator available.'); } }, @@ -122,6 +133,15 @@ module.exports = { r = this.getRandomBigInteger(range.bitLength()); } return min.add(r); + }, + + /** + * Set array of random numbers to buffer + * @param {Uint32Array} buf + */ + seedRandom: function(buf) { + randomBuffer = buf; + randomBufferIndex = buf.length; } }; diff --git a/src/index.js b/src/index.js index 711a8a55..4a2a0972 100644 --- a/src/index.js +++ b/src/index.js @@ -65,3 +65,8 @@ module.exports.crypto = require('./crypto'); * @name module:openpgp.Keyring */ module.exports.Keyring = require('./keyring'); +/** + * @see module:worker/async_proxy + * @name module:openpgp.AsyncProxy + */ +module.exports.AsyncProxy = require('./worker/async_proxy.js'); diff --git a/src/packet/all_packets.js b/src/packet/all_packets.js index 9f743830..bf8a6c94 100644 --- a/src/packet/all_packets.js +++ b/src/packet/all_packets.js @@ -46,6 +46,25 @@ module.exports = { */ newPacketFromTag: function (tag) { return new this[packetClassFromTagName(tag)](); + }, + /** + * Allocate a new packet from structured packet clone + * See {@link http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data} + * @param {Object} packetClone packet clone + * @returns {Object} new packet object with data from packet clone + */ + fromStructuredClone: function(packetClone) { + var tagName = enums.read(enums.packet, packetClone.tag) + var packet = this.newPacketFromTag(tagName); + for (var attr in packetClone) { + if (packetClone.hasOwnProperty(attr)) { + packet[attr] = packetClone[attr]; + } + } + if (packet.postCloneTypeFix) { + packet.postCloneTypeFix(); + } + return packet; } }; @@ -57,10 +76,3 @@ module.exports = { function packetClassFromTagName(tag) { return tag.substr(0, 1).toUpperCase() + tag.substr(1); } - -for (var i in enums.packet) { - var packetClass = module.exports[packetClassFromTagName(i)]; - - if (packetClass !== undefined) - packetClass.prototype.tag = enums.packet[i]; -} diff --git a/src/packet/compressed.js b/src/packet/compressed.js index 3b80e9ba..e464e91f 100644 --- a/src/packet/compressed.js +++ b/src/packet/compressed.js @@ -37,6 +37,11 @@ var enums = require('../enums.js'), * @constructor */ function Compressed() { + /** + * Packet type + * @type {module:enums.packet} + */ + this.tag = enums.packet.compressed; /** * List of packets * @type {module:packet/packetlist} diff --git a/src/packet/literal.js b/src/packet/literal.js index 40de1257..1a58d680 100644 --- a/src/packet/literal.js +++ b/src/packet/literal.js @@ -34,6 +34,7 @@ var util = require('../util.js'), * @constructor */ function Literal() { + this.tag = enums.packet.literal; this.format = 'utf8'; // default format for literal data packets this.data = ''; // literal data representation as native JavaScript string or bytes this.date = new Date(); diff --git a/src/packet/marker.js b/src/packet/marker.js index 75ee8a77..9c43a221 100644 --- a/src/packet/marker.js +++ b/src/packet/marker.js @@ -25,15 +25,19 @@ * the Marker packet.
*
* Such a packet MUST be ignored when received. + * @requires enums * @module packet/marker */ module.exports = Marker; +var enums = require('../enums.js'); + /** * @constructor */ function Marker() { + this.tag = enums.packet.marker; } /** diff --git a/src/packet/one_pass_signature.js b/src/packet/one_pass_signature.js index d5f53a9d..f330e728 100644 --- a/src/packet/one_pass_signature.js +++ b/src/packet/one_pass_signature.js @@ -37,6 +37,7 @@ var enums = require('../enums.js'), * @constructor */ function OnePassSignature() { + this.tag = enums.packet.onePassSignature; // The packet type this.version = null; // A one-octet version number. The current version is 3. this.type = null; // A one-octet signature type. Signature types are described in {@link http://tools.ietf.org/html/rfc4880#section-5.2.1|RFC4880 Section 5.2.1}. this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See {@link http://tools.ietf.org/html/rfc4880#section-9.4|RFC4880 9.4}) @@ -94,3 +95,10 @@ OnePassSignature.prototype.write = function () { return result; }; + +/** + * Fix custom types after cloning + */ +OnePassSignature.prototype.postCloneTypeFix = function() { + this.signingKeyId = type_keyid.fromClone(this.signingKeyId); +}; diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index 07284b7f..ab2ecdcc 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -175,3 +175,22 @@ Packetlist.prototype.concat = function (packetlist) { } } }; + +/** + * Allocate a new packetlist from structured packetlist clone + * See {@link http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data} + * @param {Object} packetClone packetlist clone + * @returns {Object} new packetlist object with data from packetlist clone + */ +module.exports.fromStructuredClone = function(packetlistClone) { + var packetlist = new Packetlist(); + for (var i = 0; i < packetlistClone.length; i++) { + packetlist.push(packets.fromStructuredClone(packetlistClone[i])); + if (packetlist[i].packets.length !== 0) { + packetlist[i].packets = this.fromStructuredClone(packetlist[i].packets); + } else { + packetlist[i].packets = new Packetlist(); + } + } + return packetlist; +}; \ No newline at end of file diff --git a/src/packet/public_key.js b/src/packet/public_key.js index 30935f52..f751ea60 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -42,6 +42,7 @@ var util = require('../util.js'), * @constructor */ function PublicKey() { + this.tag = enums.packet.publicKey; this.version = 4; /** Key creation date. * @type {Date} */ @@ -183,3 +184,12 @@ PublicKey.prototype.getFingerprint = function () { return crypto.hash.md5(toHash); } }; + +/** + * Fix custom types after cloning + */ +PublicKey.prototype.postCloneTypeFix = function() { + for (var i = 0; i < this.mpi.length; i++) { + this.mpi[i] = type_mpi.fromClone(this.mpi[i]); + } +}; diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js index 676046bb..dc16e30e 100644 --- a/src/packet/public_key_encrypted_session_key.js +++ b/src/packet/public_key_encrypted_session_key.js @@ -49,6 +49,7 @@ var type_keyid = require('../type/keyid.js'), * @constructor */ function PublicKeyEncryptedSessionKey() { + this.tag = enums.packet.publicKeyEncryptedSessionKey; this.version = 3; this.publicKeyId = new type_keyid(); @@ -182,3 +183,13 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = function (key) { enums.read(enums.symmetric, decoded.charCodeAt(0)); } }; + +/** + * Fix custom types after cloning + */ +PublicKeyEncryptedSessionKey.prototype.postCloneTypeFix = function() { + this.publicKeyId = type_keyid.fromClone(this.publicKeyId); + for (var i = 0; i < this.encrypted.length; i++) { + this.encrypted[i] = type_mpi.fromClone(this.encrypted[i]); + } +}; diff --git a/src/packet/public_subkey.js b/src/packet/public_subkey.js index 966db261..6e198712 100644 --- a/src/packet/public_subkey.js +++ b/src/packet/public_subkey.js @@ -17,12 +17,14 @@ /** * @requires packet/public_key + * @requires enums * @module packet/public_subkey */ module.exports = PublicSubkey; -var publicKey = require('./public_key.js'); +var publicKey = require('./public_key.js'), + enums = require('../enums.js'); /** * @constructor @@ -30,7 +32,8 @@ var publicKey = require('./public_key.js'); */ function PublicSubkey() { publicKey.call(this); -}; + this.tag = enums.packet.publicSubkey; +} PublicSubkey.prototype = new publicKey(); PublicSubkey.prototype.constructor = PublicSubkey; diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 6324ec7b..74a17aa6 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -46,6 +46,7 @@ var publicKey = require('./public_key.js'), */ function SecretKey() { publicKey.call(this); + this.tag = enums.packet.secretKey; // encrypted secret-key data this.encrypted = null; // indicator if secret-key data is available in decrypted form diff --git a/src/packet/secret_subkey.js b/src/packet/secret_subkey.js index 614c6288..839d774c 100644 --- a/src/packet/secret_subkey.js +++ b/src/packet/secret_subkey.js @@ -17,12 +17,14 @@ /** * @requires packet/secret_key + * @requires enums * @module packet/secret_subkey */ module.exports = SecretSubkey; -var secretKey = require('./secret_key.js'); +var secretKey = require('./secret_key.js'), + enums = require('../enums.js'); /** * @constructor @@ -30,6 +32,7 @@ var secretKey = require('./secret_key.js'); */ function SecretSubkey() { secretKey.call(this); + this.tag = enums.packet.secretSubkey; } SecretSubkey.prototype = new secretKey(); diff --git a/src/packet/signature.js b/src/packet/signature.js index 657f1ed2..dee37696 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -44,7 +44,7 @@ var util = require('../util.js'), * @constructor */ function Signature() { - + this.tag = enums.packet.signature; this.version = 4; this.signatureType = null; this.hashAlgorithm = null; @@ -52,7 +52,6 @@ function Signature() { this.signatureData = null; this.signedHashValue = null; - this.mpi = null; this.created = new Date(); this.signatureExpirationTime = null; @@ -638,3 +637,10 @@ Signature.prototype.isExpired = function () { } return false; }; + +/** + * Fix custom types after cloning + */ +Signature.prototype.postCloneTypeFix = function() { + this.issuerKeyId = type_keyid.fromClone(this.issuerKeyId); +}; diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index 353946d1..39b1f71b 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -27,18 +27,21 @@ * packet. * @requires crypto * @requires util + * @requires enums * @module packet/sym_encrypted_integrity_protected */ module.exports = SymEncryptedIntegrityProtected; var util = require('../util.js'), - crypto = require('../crypto'); + crypto = require('../crypto'), + enums = require('../enums.js'); /** * @constructor */ function SymEncryptedIntegrityProtected() { + this.tag = enums.packet.symEncryptedIntegrityProtected; /** The encrypted payload. */ this.encrypted = null; // string /** diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index d4ffe624..b66f2f26 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -45,7 +45,7 @@ module.exports = SymEncryptedSessionKey; * @constructor */ function SymEncryptedSessionKey() { - this.tag = 3; + this.tag = enums.packet.symEncryptedSessionKey; this.sessionKeyEncryptionAlgorithm = null; this.sessionKeyAlgorithm = 'aes256'; this.encrypted = null; @@ -140,3 +140,10 @@ SymEncryptedSessionKey.prototype.encrypt = function(passphrase) { crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm), this.sessionKeyEncryptionAlgorithm, key, private_key, true); }; + +/** + * Fix custom types after cloning + */ +SymEncryptedSessionKey.prototype.postCloneTypeFix = function() { + this.s2k = type_s2k.fromClone(this.s2k); +}; diff --git a/src/packet/symmetrically_encrypted.js b/src/packet/symmetrically_encrypted.js index 3c3020fe..faaa38a0 100644 --- a/src/packet/symmetrically_encrypted.js +++ b/src/packet/symmetrically_encrypted.js @@ -24,17 +24,20 @@ * theory other Symmetrically Encrypted Data packets or sequences of packets * that form whole OpenPGP messages). * @requires crypto + * @requires enums * @module packet/symmetrically_encrypted */ module.exports = SymmetricallyEncrypted; -var crypto = require('../crypto'); +var crypto = require('../crypto'), + enums = require('../enums.js'); /** * @constructor */ function SymmetricallyEncrypted() { + this.tag = enums.packet.symmetricallyEncrypted; this.encrypted = null; /** Decrypted packets contained within. * @type {module:packet/packetlist} */ diff --git a/src/packet/trust.js b/src/packet/trust.js index e96b3c33..73914ae5 100644 --- a/src/packet/trust.js +++ b/src/packet/trust.js @@ -1,11 +1,15 @@ /** + * @requires enums * @module packet/trust */ module.exports = Trust; +var enums = require('../enums.js'); + /** * @constructor */ function Trust() { -}; + this.tag = enums.packet.trust; +} diff --git a/src/packet/user_attribute.js b/src/packet/user_attribute.js index 42c41a65..d14727d3 100644 --- a/src/packet/user_attribute.js +++ b/src/packet/user_attribute.js @@ -32,11 +32,13 @@ * User Attribute packet as a User ID packet with opaque contents, but * an implementation may use any method desired. * module packet/user_attribute + * @requires enums * @module packet/user_attribute */ var util = require('../util.js'), - packet = require('./packet.js'); + packet = require('./packet.js'), + enums = require('../enums.js'); module.exports = UserAttribute; @@ -44,6 +46,7 @@ module.exports = UserAttribute; * @constructor */ function UserAttribute() { + this.tag = enums.packet.userAttribute; this.attributes = []; } diff --git a/src/packet/userid.js b/src/packet/userid.js index 285fdcb5..73a00d11 100644 --- a/src/packet/userid.js +++ b/src/packet/userid.js @@ -24,17 +24,20 @@ * restrictions on its content. The packet length in the header * specifies the length of the User ID. * @requires util + * @requires enums * @module packet/userid */ module.exports = Userid; -var util = require('../util.js'); +var util = require('../util.js'), + enums = require('../enums.js'); /** * @constructor */ function Userid() { + this.tag = enums.packet.userid; /** A string containing the user id. Usually in the form * John Doe * @type {String} diff --git a/src/type/keyid.js b/src/type/keyid.js index 78aa0c31..c9dcdaab 100644 --- a/src/type/keyid.js +++ b/src/type/keyid.js @@ -65,3 +65,9 @@ Keyid.prototype.isNull = function() { module.exports.mapToHex = function (keyId) { return keyId.toHex(); }; + +module.exports.fromClone = function (clone) { + var keyid = new Keyid(); + keyid.bytes = clone.bytes; + return keyid; +}; diff --git a/src/type/mpi.js b/src/type/mpi.js index 6ea7a2e3..85bd8c4e 100644 --- a/src/type/mpi.js +++ b/src/type/mpi.js @@ -100,3 +100,12 @@ MPI.prototype.toBigInteger = function () { MPI.prototype.fromBigInteger = function (bn) { this.data = bn.clone(); }; + +module.exports.fromClone = function (clone) { + clone.data.copyTo = BigInteger.prototype.copyTo; + var bn = new BigInteger(); + clone.data.copyTo(bn); + var mpi = new MPI(); + mpi.data = bn; + return mpi; +}; diff --git a/src/type/s2k.js b/src/type/s2k.js index 91701ac2..b5f71002 100644 --- a/src/type/s2k.js +++ b/src/type/s2k.js @@ -178,3 +178,12 @@ S2K.prototype.produce_key = function (passphrase, numBytes) { return result.substr(0, numBytes); }; + +module.exports.fromClone = function (clone) { + var s2k = new S2K(); + this.algorithm = clone.algorithm; + this.type = clone.type; + this.c = clone.c; + this.salt = clone.salt; + return s2k; +}; diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js new file mode 100644 index 00000000..7bedf69d --- /dev/null +++ b/src/worker/async_proxy.js @@ -0,0 +1,211 @@ +// 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 + +var crypto = require('../crypto'), + packet = require('../packet'), + key = require('../key.js'), + type_keyid = require('../type/keyid.js'); + +function AsyncProxy(path) { + this.worker = new Worker(path || 'openpgp.worker.js'); + this.worker.onmessage = this.onMessage.bind(this); + // FIFO + this.tasks = []; +} + +AsyncProxy.prototype.onMessage = function(event) { + switch (event.data.event) { + case 'method-return': + this.tasks.shift()(event.data.err, event.data.data); + break; + default: + throw new Error('Unknown Worker Event.'); + } +}; + +AsyncProxy.prototype.seedRandom = function(size) { + var buf = new Uint32Array(size); + crypto.random.getRandomValues(buf); + this.worker.postMessage({event: 'seed-random', buf: buf}); +}; + +/** + * Terminates the worker + */ +AsyncProxy.prototype.terminate = function() { + this.worker.terminate(); +}; + +/** + * Encrypts message text with keys + * @param {Array} keys array of keys, used to encrypt the message + * @param {String} text message as native JavaScript string + * @param {Function} callback receives encrypted ASCII armored message + */ +AsyncProxy.prototype.encryptMessage = function(keys, text, callback) { + keys = keys.map(function(key) { + return key.toPacketlist(); + }); + this.worker.postMessage({ + event: 'encrypt-message', + keys: keys, + text: text + }); + this.tasks.push(callback); +}; + +/** + * Signs message text and encrypts it + * @param {Array} publicKeys array of keys, used to encrypt the message + * @param {module:key~Key} privateKey private key with decrypted secret key data for signing + * @param {String} text message as native JavaScript string + * @param {Function} callback receives encrypted ASCII armored message + */ +AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text, callback) { + publicKeys = publicKeys.map(function(key) { + return key.toPacketlist(); + }); + privateKey = privateKey.toPacketlist(); + this.worker.postMessage({ + event: 'sign-and-encrypt-message', + publicKeys: publicKeys, + privateKey: privateKey, + text: text + }); + this.tasks.push(callback); +}; + +/** + * Decrypts message + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {module:message~Message} message the message object with the encrypted data + * @param {Function} callback receives decrypted message as as native JavaScript string + * or null if no literal data found + */ +AsyncProxy.prototype.decryptMessage = function(privateKey, message, callback) { + privateKey = privateKey.toPacketlist(); + this.worker.postMessage({ + event: 'decrypt-message', + privateKey: privateKey, + message: message + }); + this.tasks.push(callback); +}; + +/** + * Decrypts message and verifies signatures + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {Array} publicKeys public keys to verify signatures + * @param {module:message~Message} message the message object with signed and encrypted data + * @param {Function} callback receives decrypted message as as native JavaScript string + * with verified signatures or null if no literal data found + */ +AsyncProxy.prototype.decryptAndVerifyMessage = function(privateKey, publicKeys, message, callback) { + privateKey = privateKey.toPacketlist(); + publicKeys = publicKeys.map(function(key) { + return key.toPacketlist(); + }); + this.worker.postMessage({ + event: 'decrypt-and-verify-message', + privateKey: privateKey, + publicKeys: publicKeys, + message: message + }); + this.tasks.push(function(err, data) { + if (data) { + data.signatures = data.signatures.map(function(sig) { + sig.keyid = type_keyid.fromClone(sig.keyid); + return sig; + }); + } + callback(err, data); + }); +}; + +/** + * Signs a cleartext message + * @param {Array} privateKeys private key with decrypted secret key data to sign cleartext + * @param {String} text cleartext + * @param {Function} callback receives ASCII armored message + */ +AsyncProxy.prototype.signClearMessage = function(privateKeys, text, callback) { + privateKeys = privateKeys.map(function(key) { + return key.toPacketlist(); + }); + this.worker.postMessage({ + event: 'sign-clear-message', + privateKeys: privateKeys, + text: text + }); + this.tasks.push(callback); +}; + +/** + * Verifies signatures of cleartext signed message + * @param {Array} publicKeys public keys to verify signatures + * @param {module:cleartext~CleartextMessage} message cleartext message object with signatures + * @param {Function} callback receives cleartext with status of verified signatures + */ +AsyncProxy.prototype.verifyClearSignedMessage = function(publicKeys, message, callback) { + publicKeys = publicKeys.map(function(key) { + return key.toPacketlist(); + }); + this.worker.postMessage({ + event: 'verify-clear-signed-message', + publicKeys: publicKeys, + message: message + }); + this.tasks.push(function(err, data) { + if (data) { + data.signatures = data.signatures.map(function(sig) { + sig.keyid = type_keyid.fromClone(sig.keyid); + return sig; + }); + } + callback(err, data); + }); +}; + +/** + * 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. + * 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 " + * @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) { + this.seedRandom(Math.round(numBits / 2)); + this.worker.postMessage({ + event: 'generate-key-pair', + keyType: keyType, + numBits: numBits, + userId: userId, + passphrase: passphrase + }); + this.tasks.push(function(err, data) { + if (data) { + var packetlist = packet.List.fromStructuredClone(data.key); + data.key = new key.Key(packetlist); + } + callback(err, data); + }); +}; + +module.exports = AsyncProxy; diff --git a/src/worker/worker.js b/src/worker/worker.js new file mode 100644 index 00000000..1a9ff2b2 --- /dev/null +++ b/src/worker/worker.js @@ -0,0 +1,113 @@ +// 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 + +var window = {}; // to make UMD bundles work + +importScripts('openpgp.js'); + + +onmessage = function (event) { + var data = null, + err = null, + msg = event.data; + switch (msg.event) { + case 'seed-random': + window.openpgp.crypto.random.seedRandom(msg.buf); + break; + case 'encrypt-message': + try { + msg.keys = msg.keys.map(packetlistCloneToKey); + data = window.openpgp.encryptMessage(msg.keys, msg.text); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + case 'sign-and-encrypt-message': + try { + msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey); + msg.privateKey = packetlistCloneToKey(msg.privateKey); + data = window.openpgp.signAndEncryptMessage(msg.publicKeys, msg.privateKey, msg.text); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + case 'decrypt-message': + try { + msg.privateKey = packetlistCloneToKey(msg.privateKey); + msg.message = packetlistCloneToMessage(msg.message.packets); + data = window.openpgp.decryptMessage(msg.privateKey, msg.message); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + case 'decrypt-and-verify-message': + try { + msg.privateKey = packetlistCloneToKey(msg.privateKey); + msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey); + msg.message = packetlistCloneToMessage(msg.message.packets); + data = window.openpgp.decryptAndVerifyMessage(msg.privateKey, msg.publicKeys, msg.message); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + case 'sign-clear-message': + try { + msg.privateKeys = msg.privateKeys.map(packetlistCloneToKey); + data = window.openpgp.signClearMessage(msg.privateKeys, msg.text); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + case 'verify-clear-signed-message': + try { + msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey); + var packetlist = window.openpgp.packet.List.fromStructuredClone(msg.message.packets); + msg.message = new window.openpgp.cleartext.CleartextMessage(msg.message.text, packetlist); + data = window.openpgp.verifyClearSignedMessage(msg.publicKeys, msg.message); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + case 'generate-key-pair': + try { + data = window.openpgp.generateKeyPair(msg.keyType, msg.numBits, msg.userId, msg.passphrase); + data.key = data.key.toPacketlist(); + } catch (e) { + err = e; + } + postMessage({event: 'method-return', data: data, err: err}); + break; + default: + throw new Error('Unknown Worker Event.'); + } +}; + +function packetlistCloneToKey(packetlistClone) { + var packetlist = window.openpgp.packet.List.fromStructuredClone(packetlistClone); + return new window.openpgp.key.Key(packetlist); +} + +function packetlistCloneToMessage(packetlistClone) { + var packetlist = window.openpgp.packet.List.fromStructuredClone(packetlistClone); + return new window.openpgp.message.Message(packetlist); +} \ No newline at end of file