Add web worker support. Load the whole library in a web worker
and make the high-level API accessible from an asynchronous proxy. Entropy is seeded to worker on each generateKeyPair() call. Allow serialization of packets and custom types for messaging API.
This commit is contained in:
parent
4f2100fa40
commit
3612fc12dc
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -25,15 +25,19 @@
|
|||
* the Marker packet.<br/>
|
||||
* <br/>
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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]);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = [];
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <john@example.com>
|
||||
* @type {String}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
211
src/worker/async_proxy.js
Normal file
211
src/worker/async_proxy.js
Normal file
|
@ -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<module:key~Key>} 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<module:key~Key>} 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<module:key~Key>} 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<module:key~Key>} 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<module:key~Key>} 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 <username@email.com>"
|
||||
* @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;
|
113
src/worker/worker.js
Normal file
113
src/worker/worker.js
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user