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