Skip to content

Commit

Permalink
making webassembly optional, ensuring retry button works when wrong p…
Browse files Browse the repository at this point in the history
…assword is provided

Tested configurations:
- browser with WASM support (Firefox 68.0.2)
  - creates paste with zlib compression, no password
  - creates paste with zlib compression, with password
  - reads paste with zlib compression, no password
  - reads paste with zlib compression, with password + retry button works
  - reads paste without compression, no password
  - reads paste without compression, with password + retry button works
- browser without WASM support (Chromium 76.0.3809.100, started via `chromium-browser --js-flags=--noexpose_wasm`)
  - creates paste without compression, no password, but shows WASM warning
  - creates paste without compression, with password, but shows WASM warning
  - fails to read paste with zlib compression, no password + shows WASM error
  - fails to read paste with zlib compression, with password + shows WASM error
  - reads paste without compression, no password
  - reads paste without compression, with password + retry button works
  • Loading branch information
elrido committed Sep 8, 2019
1 parent 7a85900 commit 5471757
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 74 deletions.
115 changes: 47 additions & 68 deletions js/privatebin.js
Expand Up @@ -780,15 +780,19 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @private
* @param {string} message
* @param {string} mode
* @param {object} zlib
* @throws {string}
* @return {ArrayBuffer} data
*/
async function compress(message, mode)
async function compress(message, mode, zlib)
{
message = stringToArraybuffer(
utf16To8(message)
);
if (mode === 'zlib') {
let zlib = (await z);
if (typeof zlib === 'undefined') {
throw 'Error compressing paste, due to missing WebAssembly support.'
}
return zlib.deflate(message).buffer;
}
return message;
Expand All @@ -803,16 +807,16 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @private
* @param {ArrayBuffer} data
* @param {string} mode
* @param {object} zlib
* @throws {string}
* @return {string} message
*/
async function decompress(data, mode)
async function decompress(data, mode, zlib)
{
if (mode === 'zlib' || mode === 'none') {
if (mode === 'zlib') {
let zlib = (await z);
if (typeof zlib === 'undefined') {
Alert.showError('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.')
return '';
throw 'Error decompressing paste, due to missing WebAssembly support.'
}
data = zlib.inflate(
new Uint8Array(data)
Expand Down Expand Up @@ -962,12 +966,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
me.cipher = async function(key, password, message, adata)
{
let zlib = (await z);
// AES in Galois Counter Mode, keysize 256 bit,
// authentication tag 128 bit, 10000 iterations in key derivation
const compression = (
typeof (await z) === 'undefined' ?
typeof zlib === 'undefined' ?
'none' : // client lacks support for WASM
$('body').data('compression') || 'zlib'
($('body').data('compression') || 'zlib')
),
spec = [
getRandomBytes(16), // initialization vector
Expand Down Expand Up @@ -997,7 +1002,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
await window.crypto.subtle.encrypt(
cryptoSettings(JSON.stringify(adata), spec),
await deriveKey(key, password, spec),
await compress(message, compression)
await compress(message, compression, zlib)
).catch(Alert.showError)
)
),
Expand All @@ -1018,7 +1023,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
me.decipher = async function(key, password, data)
{
let adataString, spec, cipherMessage;
let adataString, spec, cipherMessage, plaintext;
let zlib = (await z);
if (data instanceof Array) {
// version 2
adataString = JSON.stringify(data[1]);
Expand All @@ -1045,20 +1051,29 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
spec[0] = atob(spec[0]);
spec[1] = atob(spec[1]);
if (spec[7] === 'zlib') {
if (typeof zlib === 'undefined') {
throw 'Error decompressing paste, due to missing WebAssembly support.'
}
}
try {
return await decompress(
await window.crypto.subtle.decrypt(
cryptoSettings(adataString, spec),
await deriveKey(key, password, spec),
stringToArraybuffer(
atob(cipherMessage)
)
).catch(Alert.showError),
spec[7]
plaintext = await window.crypto.subtle.decrypt(
cryptoSettings(adataString, spec),
await deriveKey(key, password, spec),
stringToArraybuffer(
atob(cipherMessage)
)
);
} catch(err) {
console.error(err);
return '';
}
try {
return await decompress(plaintext, spec[7], zlib);
} catch(err) {
Alert.showError(err);
return err;
}
};

/**
Expand Down Expand Up @@ -4522,7 +4537,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {

// if all tries failed, we can only return an error
if (plaindata.length === 0) {
throw 'failed to decipher data';
return false;
}

return plaindata;
Expand Down Expand Up @@ -4551,8 +4566,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
if (password.length === 0) {
throw 'waiting on user to provide a password';
} else {
displayDecryptionError('failed to decipher paste text: Incorrect password?');
throw 'waiting on user to provide correct password';
Alert.hideLoading();
// reset password, so it can be re-entered
Prompt.reset();
TopNav.showRetryButton();
throw 'Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.';
}
}

Expand Down Expand Up @@ -4642,27 +4660,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
});
}

/**
* displays and logs decryption errors
*
* @name PasteDecrypter.displayDecryptionError
* @private
* @function
* @param {string} message
*/
function displayDecryptionError(message)
{
Alert.hideLoading();

// log detailed error, but display generic translation
console.error(message);
Alert.showError('Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.');

// reset password, so it can be re-entered
Prompt.reset();
TopNav.showRetryButton();
}

/**
* show decrypted text in the display area, including discussion (if open)
*
Expand Down Expand Up @@ -4714,7 +4711,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
.catch((err) => {
// wait for the user to type in the password,
// then PasteDecrypter.run will be called again
console.error(err);
Alert.showError(err);
});
};

Expand Down Expand Up @@ -4818,34 +4815,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
'subtle' in window.crypto &&
'encrypt' in window.crypto.subtle &&
'decrypt' in window.crypto.subtle &&
'Uint8Array' in window &&
'Uint32Array' in window
)) {
return true;
}

if (!(
'WebAssembly' in window &&
'instantiate' in window.WebAssembly
)) {
return true;
}
try {
// [\0, 'a', 's', 'm', (uint_32) 1] - smallest valid wasm module
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if (
!(
module instanceof WebAssembly.Module &&
new WebAssembly.Instance(module) instanceof WebAssembly.Instance
)
) {
return true;
}
} catch (e) {
return true;
}

// not checking for async/await, ES6, Promise or Uint8Array support,
// as most browsers introduced these earlier then webassembly and webcrypto:
// not checking for async/await, ES6 or Promise support, as most
// browsers introduced these earlier then webassembly and webcrypto:
// https://github.com/PrivateBin/PrivateBin/pull/431#issuecomment-493129359

return false;
Expand Down Expand Up @@ -4881,7 +4858,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}

z = zlib.catch(function () {
Alert.showWarning('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.');
if ($('body').data('compression') !== 'none') {
Alert.showWarning('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.');
}
});
return true;
}
Expand Down
11 changes: 7 additions & 4 deletions js/test/CryptTool.js
Expand Up @@ -8,9 +8,6 @@ describe('CryptTool', function () {
await new Promise(resolve => setTimeout(resolve, 1900));
});

// ensure zlib is getting loaded
$.PrivateBin.InitialCheck.init();

this.timeout(30000);
it('can en- and decrypt any message', function () {
jsc.assert(jsc.forall(
Expand All @@ -21,13 +18,15 @@ describe('CryptTool', function () {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.InitialCheck.init();
window.crypto = new WebCrypto();
message = message.trim();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
key, password, cipherMessage
);
clean();
return message === plaintext;
Expand Down Expand Up @@ -182,6 +181,8 @@ describe('CryptTool', function () {
let message = fs.readFileSync('test/compression-sample.txt', 'utf8'),
clean = jsdom();
window.crypto = new WebCrypto();
// ensure zlib is getting loaded
$.PrivateBin.InitialCheck.init();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
'foo', 'bar', message, []
),
Expand Down Expand Up @@ -225,6 +226,8 @@ isWhile : interp (while expr sBody) (MemElem mem) =
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
let clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.InitialCheck.init();
window.crypto = new WebCrypto();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
Expand Down
2 changes: 1 addition & 1 deletion tpl/bootstrap.php
Expand Up @@ -71,7 +71,7 @@
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-dsFOXy6/2JHcWi9jwtIIBmAwkRc/2cHDON5YONEo9yFZ7Mt//UFszzk3/kKM77JRDvkHC9gvK/ucgsYT+gyUVw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-tTyV/T13WEwhn9bKY1N0PVu5UFctbDY1qosTTrslVq0R3vPTPjjxSMbUZ3FZBf01rXu39HPV/ibQiD2fOEjYcA==" crossorigin="anonymous"></script>
<!--[if IE]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
<![endif]-->
Expand Down
2 changes: 1 addition & 1 deletion tpl/page.php
Expand Up @@ -49,7 +49,7 @@
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-dsFOXy6/2JHcWi9jwtIIBmAwkRc/2cHDON5YONEo9yFZ7Mt//UFszzk3/kKM77JRDvkHC9gvK/ucgsYT+gyUVw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-tTyV/T13WEwhn9bKY1N0PVu5UFctbDY1qosTTrslVq0R3vPTPjjxSMbUZ3FZBf01rXu39HPV/ibQiD2fOEjYcA==" crossorigin="anonymous"></script>
<!--[if IE]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
<![endif]-->
Expand Down

0 comments on commit 5471757

Please sign in to comment.