Remove OpenPGP support for IE and Node, and es6-promise polyfill

This commit is contained in:
djmaze 2021-05-03 17:05:50 +02:00
parent 8c454ccd9d
commit be76df33b6
13 changed files with 198 additions and 1824 deletions

View file

@ -139,7 +139,7 @@ RainLoop 1.15 vs SnappyMail
|OpenPGP |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|openpgp.min.js | 330.742 | 330.300 |102.388 |102.388 | 84.241 | 84.121 |
|openpgp.min.js | 330.742 | 320.189 |102.388 | 98.725 | 84.241 | 81.253 |
|openpgp.worker | 1.499 | 1.125 | 824 | 567 | 695 | 467 |
For a user its around 66% smaller and faster than traditional RainLoop.

File diff suppressed because it is too large Load diff

View file

@ -15,6 +15,7 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
self.window={};
importScripts('openpgp.js');
var openpgp = window.openpgp;

View file

@ -1 +1 @@
importScripts("openpgp.min.js");var openpgp=window.openpgp,MIN_SIZE_RANDOM_BUFFER=4e4,MAX_SIZE_RANDOM_BUFFER=6e4;function configure(e){for(var n in e)openpgp.config[n]=e[n]}function seedRandom(e){e instanceof Uint8Array||(e=new Uint8Array(e)),openpgp.crypto.random.randomBuffer.set(e)}function delegate(e,n,o){"function"==typeof openpgp[n]?(o=openpgp.packet.clone.parseClonedPackets(o,n),openpgp[n](o).then((function(n){response({id:e,event:"method-return",data:openpgp.packet.clone.clonePackets(n)})})).catch((function(n){response({id:e,event:"method-return",err:n.message,stack:n.stack})}))):response({id:e,event:"method-return",err:"Unknown Worker Event"})}function response(e){openpgp.crypto.random.randomBuffer.size<MIN_SIZE_RANDOM_BUFFER&&self.postMessage({event:"request-seed"}),self.postMessage(e,openpgp.util.getTransferables.call(openpgp.util,e.data))}openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER),self.onmessage=e=>{var n=e.data||{};switch(n.event){case"configure":configure(n.config);break;case"seed-random":seedRandom(n.buf);break;default:delegate(n.id,n.event,n.options||{})}};
self.window={};importScripts("openpgp.min.js");var openpgp=window.openpgp,MIN_SIZE_RANDOM_BUFFER=4e4,MAX_SIZE_RANDOM_BUFFER=6e4;function configure(e){for(var n in e)openpgp.config[n]=e[n]}function seedRandom(e){e instanceof Uint8Array||(e=new Uint8Array(e)),openpgp.crypto.random.randomBuffer.set(e)}function delegate(e,n,o){"function"==typeof openpgp[n]?(o=openpgp.packet.clone.parseClonedPackets(o,n),openpgp[n](o).then((function(n){response({id:e,event:"method-return",data:openpgp.packet.clone.clonePackets(n)})})).catch((function(n){response({id:e,event:"method-return",err:n.message,stack:n.stack})}))):response({id:e,event:"method-return",err:"Unknown Worker Event"})}function response(e){openpgp.crypto.random.randomBuffer.size<MIN_SIZE_RANDOM_BUFFER&&self.postMessage({event:"request-seed"}),self.postMessage(e,openpgp.util.getTransferables.call(openpgp.util,e.data))}openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER),self.onmessage=e=>{var n=e.data||{};switch(n.event){case"configure":configure(n.config);break;case"seed-random":seedRandom(n.buf);break;default:delegate(n.id,n.event,n.options||{})}};

View file

@ -26,8 +26,6 @@ import util from '../util.js';
import config from '../config';
import asmCrypto from 'asmcrypto-lite';
const webCrypto = util.getWebCrypto(); // no GCM support in IE11, Safari 9
const nodeCrypto = util.getNodeCrypto();
const Buffer = util.getNodeBuffer();
export const ivLength = 12; // size of the IV in bytes
const TAG_LEN = 16; // size of the tag in bytes
@ -48,11 +46,9 @@ export function encrypt(cipher, plaintext, key, iv) {
if (webCrypto && config.use_native && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
return webEncrypt(plaintext, key, iv);
} else if (nodeCrypto && config.use_native) { // Node crypto library
return nodeEncrypt(plaintext, key, iv) ;
} else { // asm.js fallback
return Promise.resolve(asmCrypto.AES_GCM.encrypt(plaintext, key, iv));
}
// asm.js fallback
return Promise.resolve(asmCrypto.AES_GCM.encrypt(plaintext, key, iv));
}
/**
@ -70,11 +66,9 @@ export function decrypt(cipher, ciphertext, key, iv) {
if (webCrypto && config.use_native && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
return webDecrypt(ciphertext, key, iv);
} else if (nodeCrypto && config.use_native) { // Node crypto library
return nodeDecrypt(ciphertext, key, iv);
} else { // asm.js fallback
return Promise.resolve(asmCrypto.AES_GCM.decrypt(ciphertext, key, iv));
}
// asm.js fallback
return Promise.resolve(asmCrypto.AES_GCM.decrypt(ciphertext, key, iv));
}
@ -96,22 +90,3 @@ function webDecrypt(ct, key, iv) {
.then(keyObj => webCrypto.decrypt({ name: ALGO, iv }, keyObj, ct))
.then(pt => new Uint8Array(pt));
}
function nodeEncrypt(pt, key, iv) {
pt = new Buffer(pt);
key = new Buffer(key);
iv = new Buffer(iv);
const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-gcm', key, iv);
const ct = Buffer.concat([en.update(pt), en.final(), en.getAuthTag()]); // append auth tag to ciphertext
return Promise.resolve(new Uint8Array(ct));
}
function nodeDecrypt(ct, key, iv) {
ct = new Buffer(ct);
key = new Buffer(key);
iv = new Buffer(iv);
const de = new nodeCrypto.createDecipheriv('aes-' + (key.length * 8) + '-gcm', key, iv);
de.setAuthTag(ct.slice(ct.length - TAG_LEN, ct.length)); // read auth tag at end of ciphertext
const pt = Buffer.concat([de.update(ct.slice(0, ct.length - TAG_LEN)), de.final()]);
return Promise.resolve(new Uint8Array(pt));
}

View file

@ -15,62 +15,26 @@ import md5 from './md5.js';
import ripemd from './ripe-md.js';
import util from '../../util.js';
const rusha = new Rusha(),
nodeCrypto = util.getNodeCrypto(),
Buffer = util.getNodeBuffer();
function node_hash(type) {
return function (data) {
var shasum = nodeCrypto.createHash(type);
shasum.update(new Buffer(data));
return new Uint8Array(shasum.digest());
};
}
var hash_fns;
if(nodeCrypto) { // Use Node native crypto for all hash functions
hash_fns = {
md5: node_hash('md5'),
sha1: node_hash('sha1'),
sha224: node_hash('sha224'),
sha256: node_hash('sha256'),
sha384: node_hash('sha384'),
sha512: node_hash('sha512'),
ripemd: node_hash('ripemd160')
};
} else { // Use JS fallbacks
hash_fns = {
/** @see module:crypto/hash/md5 */
md5: md5,
/** @see module:rusha */
sha1: function(data) {
return util.str2Uint8Array(util.hex2bin(rusha.digest(data)));
},
/** @see module:crypto/hash/sha.sha224 */
sha224: sha.sha224,
/** @see module:asmcrypto */
sha256: asmCrypto.SHA256.bytes,
/** @see module:crypto/hash/sha.sha384 */
sha384: sha.sha384,
/** @see module:crypto/hash/sha.sha512 */
sha512: sha.sha512,
/** @see module:crypto/hash/ripe-md */
ripemd: ripemd
};
}
const rusha = new Rusha();
export default {
md5: hash_fns.md5,
sha1: hash_fns.sha1,
sha224: hash_fns.sha224,
sha256: hash_fns.sha256,
sha384: hash_fns.sha384,
sha512: hash_fns.sha512,
ripemd: hash_fns.ripemd,
/** @see module:crypto/hash/md5 */
md5: md5,
/** @see module:rusha */
sha1: function(data) {
return util.str2Uint8Array(util.hex2bin(rusha.digest(data)));
},
/** @see module:crypto/hash/sha.sha224 */
sha224: sha.sha224,
/** @see module:asmcrypto */
sha256: asmCrypto.SHA256.bytes,
/** @see module:crypto/hash/sha.sha384 */
sha384: sha.sha384,
/** @see module:crypto/hash/sha.sha512 */
sha512: sha.sha512,
/** @see module:crypto/hash/ripe-md */
ripemd: ripemd,
/**
* Create a hash on the specified data using the specified algorithm

View file

@ -172,9 +172,6 @@ export default function RSA() {
};
keys = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
if (typeof keys.then !== 'function') { // IE11 KeyOperation
keys = util.promisifyIE11Op(keys, 'Error generating RSA key pair.');
}
}
return keys.then(exportKey).then(function(key) {
@ -189,11 +186,7 @@ export default function RSA() {
function exportKey(keypair) {
// export the generated keys as JsonWebKey (JWK)
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33
var key = webCrypto.exportKey('jwk', keypair.privateKey);
if (typeof key.then !== 'function') { // IE11 KeyOperation
key = util.promisifyIE11Op(key, 'Error exporting RSA key pair.');
}
return key;
return webCrypto.exportKey('jwk', keypair.privateKey);
}
function decodeKey(jwk) {

View file

@ -27,7 +27,6 @@
import type_mpi from '../type/mpi.js';
import util from '../util.js';
const nodeCrypto = util.detectNode() && require('crypto');
export default {
/**
@ -83,9 +82,6 @@ export default {
window.crypto.getRandomValues(buf);
} else if (typeof window !== 'undefined' && typeof window.msCrypto === 'object' && typeof window.msCrypto.getRandomValues === 'function') {
window.msCrypto.getRandomValues(buf);
} else if (nodeCrypto) {
var bytes = nodeCrypto.randomBytes(buf.length);
buf.set(bytes);
} else if (this.randomBuffer.buffer) {
this.randomBuffer.get(buf);
} else {

View file

@ -32,7 +32,7 @@ import config from './config';
*/
export default function HKP(keyServerBaseUrl) {
this._baseUrl = keyServerBaseUrl ? keyServerBaseUrl : config.keyserver;
this._fetch = typeof window !== 'undefined' ? window.fetch : require('node-fetch');
this._fetch = window.fetch;
}
/**
@ -83,4 +83,4 @@ HKP.prototype.upload = function(publicKeyArmored) {
},
body: 'keytext=' + encodeURIComponent(publicKeyArmored)
});
};
};

View file

@ -63,11 +63,7 @@ export default class LocalStore
prefix = prefix || 'openpgp-';
this.publicKeysItem = prefix + this.publicKeysItem;
this.privateKeysItem = prefix + this.privateKeysItem;
if (typeof window !== 'undefined' && window.localStorage) {
this.storage = window.localStorage;
} else {
this.storage = new (require('node-localstorage').LocalStorage)(config.node_store);
}
this.storage = window.localStorage;
}
/**

View file

@ -38,8 +38,6 @@ import * as key from './key.js';
import config from './config/config.js';
import util from './util';
import AsyncProxy from './worker/async_proxy.js';
import es6Promise from 'es6-promise';
es6Promise.polyfill(); // load ES6 Promises polyfill
//////////////////////////

View file

@ -38,8 +38,6 @@ import util from '../util.js';
import crypto from '../crypto';
import enums from '../enums.js';
import asmCrypto from 'asmcrypto-lite';
const nodeCrypto = util.getNodeCrypto();
const Buffer = util.getNodeBuffer();
const VERSION = 1; // A one-octet version number of the data packet.
@ -144,36 +142,9 @@ SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm
function aesEncrypt(algo, prefix, pt, key) {
if(nodeCrypto) { // Node crypto library.
return nodeEncrypt(algo, prefix, pt, key);
} else { // asm.js fallback
return asmCrypto.AES_CFB.encrypt(util.concatUint8Array([prefix, pt]), key);
}
return asmCrypto.AES_CFB.encrypt(util.concatUint8Array([prefix, pt]), key);
}
function aesDecrypt(algo, ct, key) {
let pt;
if(nodeCrypto) { // Node crypto library.
pt = nodeDecrypt(algo, ct, key);
} else { // asm.js fallback
pt = asmCrypto.AES_CFB.decrypt(ct, key);
}
return pt.subarray(crypto.cipher[algo].blockSize + 2, pt.length); // Remove random prefix
return asmCrypto.AES_CFB.decrypt(ct, key).subarray(crypto.cipher[algo].blockSize + 2, pt.length); // Remove random prefix
}
function nodeEncrypt(algo, prefix, pt, key) {
key = new Buffer(key);
const iv = new Buffer(new Uint8Array(crypto.cipher[algo].blockSize));
const cipherObj = new nodeCrypto.createCipheriv('aes-' + algo.substr(3,3) + '-cfb', key, iv);
const ct = cipherObj.update(new Buffer(util.concatUint8Array([prefix, pt])));
return new Uint8Array(ct);
}
function nodeDecrypt(algo, ct, key) {
ct = new Buffer(ct);
key = new Buffer(key);
const iv = new Buffer(new Uint8Array(crypto.cipher[algo].blockSize));
const decipherObj = new nodeCrypto.createDecipheriv('aes-' + algo.substr(3,3) + '-cfb', key, iv);
const pt = decipherObj.update(ct);
return new Uint8Array(pt);
}

View file

@ -485,71 +485,11 @@ export default {
}
},
/**
* Wraps a generic synchronous function in an ES6 Promise.
* @param {Function} fn The function to be wrapped
* @return {Function} The function wrapped in a Promise
*/
promisify: function(fn) {
return function() {
var args = arguments;
return new Promise(function(resolve) {
var result = fn.apply(null, args);
resolve(result);
});
};
},
/**
* Converts an IE11 web crypro api result to a promise.
* This is required since IE11 implements an old version of the
* Web Crypto specification that does not use promises.
* @param {Object} cryptoOp The return value of an IE11 web cryptro api call
* @param {String} errmsg An error message for a specific operation
* @return {Promise} The resulting Promise
*/
promisifyIE11Op: function(cryptoOp, errmsg) {
return new Promise(function(resolve, reject) {
cryptoOp.onerror = function () {
reject(new Error(errmsg));
};
cryptoOp.oncomplete = function (e) {
resolve(e.target.result);
};
});
},
/**
* Detect Node.js runtime.
*/
detectNode: function() {
return typeof window === 'undefined';
},
/**
* Get native Node.js crypto api. The default configuration is to use
* the api when available. But it can also be deactivated with config.use_native
* @return {Object} The crypto module or 'undefined'
*/
getNodeCrypto: function() {
if (!this.detectNode() || !config.use_native) {
return;
}
return require('crypto');
},
/**
* Get native Node.js Buffer constructor. This should be used since
* Buffer is not available under browserify.
* @return {Function} The Buffer constructor or 'undefined'
*/
getNodeBuffer: function() {
if (!this.detectNode()) {
return;
}
return require('buffer').Buffer;
}
};