aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/bbcode.php38
-rw-r--r--view/js/crypto.js86
-rw-r--r--view/php/theme_init.php1
-rw-r--r--view/tpl/chat.tpl4
-rw-r--r--view/tpl/comment_item.tpl2
-rw-r--r--view/tpl/jot.tpl2
6 files changed, 104 insertions, 29 deletions
diff --git a/include/bbcode.php b/include/bbcode.php
index 848d117fb..b39822b05 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -247,41 +247,39 @@ function bb_parse_crypt($match) {
$matches = [];
$attributes = $match[1];
-
- $algorithm = "";
+ $hint = '';
+ $algorithm = '';
preg_match("/alg='(.*?)'/ism", $attributes, $matches);
- if ($matches[1] != "")
- $algorithm = $matches[1];
-
- preg_match("/alg=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
- if ($matches[1] != "")
- $algorithm = $matches[1];
+ $algorithm = $matches[1] ?? '';
- $hint = "";
+ if (!$algorithm) {
+ preg_match("/alg=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ $algorithm = $matches[1] ?? '';
+ }
preg_match("/hint='(.*?)'/ism", $attributes, $matches);
- if ($matches[1] != "")
- $hint = $matches[1];
- preg_match("/hint=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
- if ($matches[1] != "")
- $hint = $matches[1];
+ $hint = $matches[1] ?? '';
+
+ if (!$hint) {
+ preg_match("/hint=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ $hint = $matches[1] ?? '';
+ }
$x = random_string();
- $f = 'hz_decrypt';
+ $f = 'sodium_decrypt';
- //legacy cryptojs support
- if(plugin_is_installed('cryptojs')) {
- $f = ((in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) ? 'hz_decrypt' : 'red_decrypt');
+ if (in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) {
+ $f = 'hz_decrypt'; // deprecated
}
$onclick = 'onclick="' . $f . '(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');"';
$label = t('Encrypted content');
- $Text = '<br /><div id="' . $x . '"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div><br />';
+ $text = '<br /><div id="' . $x . '"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div><br />';
- return $Text;
+ return $text;
}
/**
diff --git a/view/js/crypto.js b/view/js/crypto.js
index 14bc1e0a2..55b9aea11 100644
--- a/view/js/crypto.js
+++ b/view/js/crypto.js
@@ -15,6 +15,82 @@ function str_rot13 (str) {
});
}
+async function sodium_encrypt(element) {
+ if (!window.sodium) {
+ window.sodium = await SodiumPlus.auto();
+ }
+
+ if (typeof tinyMCE !== typeof undefined) {
+ tinyMCE.triggerSave(false,true);
+ }
+
+ let message = $(element).val();
+ let password = prompt(aStr['passphrase']);
+
+ if (!password) {
+ return false;
+ }
+
+ let hint = bin2hex(prompt(aStr['passhint']));
+
+ let salt = await sodium.randombytes_buf(16);
+ let nonce = await sodium.randombytes_buf(24);
+ let key = await sodium.crypto_pwhash(
+ 32,
+ password,
+ salt,
+ sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
+ sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
+ );
+
+ // Message can be a string, buffer, array, etc.
+ let ciphertext = await sodium.crypto_secretbox(message, nonce, key);
+ delete message, password, key;
+
+ let s = await sodium.sodium_bin2hex(salt);
+ let n = await sodium.sodium_bin2hex(nonce);
+ let c = await sodium.sodium_bin2hex(ciphertext);
+ let encrypted = window.btoa(s + '.' + n + '.' + c);
+ let val = "[crypt alg='XSalsa20' hint='" + hint + "']" + encrypted + '[/crypt]';
+
+ $(element).val(val);
+}
+
+async function sodium_decrypt(alg, hint, encrypted, element) {
+ if (alg !== 'XSalsa20') {
+ alert('Unsupported algorithm');
+ return false;
+ }
+
+ let arr = window.atob(encrypted).split('.');
+ let salt = await sodium.sodium_hex2bin(arr[0]);
+ let nonce = await sodium.sodium_hex2bin(arr[1]);
+ let ciphertext = await sodium.sodium_hex2bin(arr[2]);
+ let password = prompt((hint.length) ? hex2bin(hint) : aStr['passphrase']);
+
+ if (!password) {
+ return false;
+ }
+
+ let key = await sodium.crypto_pwhash(
+ 32,
+ password,
+ salt,
+ sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
+ sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
+ );
+
+ let decrypted = await sodium.crypto_secretbox_open(ciphertext, nonce, key);
+ delete password, key;
+
+ if ($(element).css('display') === 'none' && typeof tinyMCE !== typeof undefined) {
+ tinyMCE.activeEditor.setContent(newdiv);
+ }
+ else {
+ $(element).html(decrypted.toString('utf-8'));
+ }
+}
+
function hz_encrypt(alg, elem) {
var enc_text = '';
var newdiv = '';
@@ -33,7 +109,7 @@ function hz_encrypt(alg, elem) {
var enc_key = bin2hex(passphrase);
// If you don't provide a key you get rot13, which doesn't need a key
- // but consequently isn't secure.
+ // but consequently isn't secure.
if(! enc_key)
alg = 'rot13';
@@ -44,7 +120,7 @@ function hz_encrypt(alg, elem) {
if(alg == 'AES-128-CCM') {
// This is the prompt we're going to use when the receiver tries to open it.
- // Maybe "Grandma's maiden name" or "our secret place" or something.
+ // Maybe "Grandma's maiden name" or "our secret place" or something.
var enc_hint = bin2hex(prompt(aStr['passhint']));
@@ -62,7 +138,7 @@ function hz_encrypt(alg, elem) {
// property of our source element - because a tinymce instance
// will have display "none". If a normal textarea such as in a comment
// box has display "none" you wouldn't be able to type in it.
-
+
if($(elem).css('display') == 'none' && typeof tinyMCE !== "undefined") {
tinyMCE.activeEditor.setContent(newdiv);
}
@@ -98,8 +174,8 @@ function hz_decrypt(alg, hint, text, elem) {
enc_key = '';
// Not sure whether to drop this back in the conversation display.
- // It probably needs a lightbox or popup window because any conversation
- // updates could
+ // It probably needs a lightbox or popup window because any conversation
+ // updates could
// wipe out the text and make you re-enter the key if it was in the
// conversation. For now we do that so you can read it.
diff --git a/view/php/theme_init.php b/view/php/theme_init.php
index b08651689..50da8b5f9 100644
--- a/view/php/theme_init.php
+++ b/view/php/theme_init.php
@@ -26,6 +26,7 @@ head_add_js('/library/readmore.js/readmore.js');
head_add_js('/library/jgrowl/jquery.jgrowl.min.js');
head_add_js('/library/sjcl/sjcl.js');
+head_add_js('/library/sodium-plus/dist/sodium-plus.min.js');
head_add_js('acl.js');
head_add_js('webtoolkit.base64.js');
diff --git a/view/tpl/chat.tpl b/view/tpl/chat.tpl
index da8da30f2..a0e528894 100644
--- a/view/tpl/chat.tpl
+++ b/view/tpl/chat.tpl
@@ -70,7 +70,7 @@
</div>
{{if $feature_encrypt}}
<div class="btn-group me-2 d-none d-md-flex">
- <button id="chat-encrypt-wrapper" class="btn btn-outline-secondary btn-sm" onclick="hz_encrypt('{{$cipher}}', '#chatText'); return false;">
+ <button id="chat-encrypt-wrapper" class="btn btn-outline-secondary btn-sm" onclick="sodium_encrypt('#chatText'); return false;">
<i id="chat-encrypt" class="fa fa-key jot-icons" title="{{$encrypt}}" ></i>
</button>
</div>
@@ -83,7 +83,7 @@
<a class="dropdown-item" href="#" onclick="chatJotGetLink(); return false;" ><i class="fa fa-link"></i>&nbsp;{{$insert}}</a>
{{if $feature_encrypt}}
<div class="dropdown-divider"></div>
- <a class="dropdown-item" href="#" onclick="hz_encrypt('{{$cipher}}', '#chatText'); return false;"><i class="fa fa-key"></i>&nbsp;{{$encrypt}}</a>
+ <a class="dropdown-item" href="#" onclick="sodium_encrypt('#chatText'); return false;"><i class="fa fa-key"></i>&nbsp;{{$encrypt}}</a>
{{/if}}
</div>
</div>
diff --git a/view/tpl/comment_item.tpl b/view/tpl/comment_item.tpl
index d29193901..891d901c9 100644
--- a/view/tpl/comment_item.tpl
+++ b/view/tpl/comment_item.tpl
@@ -50,7 +50,7 @@
</div>
{{if $feature_encrypt}}
<div class="btn-group me-2">
- <button class="btn btn-outline-secondary btn-sm border-0" title="{{$encrypt}}" onclick="hz_encrypt('{{$cipher}}','#comment-edit-text-' + '{{$id}}'); return false;">
+ <button class="btn btn-outline-secondary btn-sm border-0" title="{{$encrypt}}" onclick="sodium_encrypt('#comment-edit-text-' + '{{$id}}'); return false;">
<i class="fa fa-key comment-icon"></i>
</button>
</div>
diff --git a/view/tpl/jot.tpl b/view/tpl/jot.tpl
index 0ffdc0517..eedd92170 100644
--- a/view/tpl/jot.tpl
+++ b/view/tpl/jot.tpl
@@ -160,7 +160,7 @@
</button>
{{/if}}
{{if $feature_encrypt}}
- <button type="button" id="profile-encrypt-wrapper" class="btn btn-outline-secondary btn-sm border-0" title="{{$encrypt}}" onclick="hz_encrypt('{{$cipher}}','#profile-jot-text');return false;">
+ <button type="button" id="profile-encrypt-wrapper" class="btn btn-outline-secondary btn-sm border-0" title="{{$encrypt}}" onclick="sodium_encrypt('#profile-jot-text'); return false;">
<i id="profile-encrypt" class="fa fa-key jot-icons"></i>
</button>
{{/if}}