mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-20 03:35:13 +00:00
b2b encryption updates
This commit is contained in:
parent
cf53c32c48
commit
18d5ac0267
3 changed files with 85 additions and 59 deletions
|
@ -274,53 +274,54 @@ function bb_parse_crypt($match)
|
||||||
{
|
{
|
||||||
|
|
||||||
$matches = [];
|
$matches = [];
|
||||||
$attributes = $match[1];
|
|
||||||
$hint = '';
|
$hint = '';
|
||||||
$algorithm = '';
|
$algorithm = '';
|
||||||
|
$payload = $match[1];
|
||||||
|
|
||||||
|
if (isset($match[2])) {
|
||||||
|
// backwards compatibility
|
||||||
|
|
||||||
|
$attributes = $match[1];
|
||||||
|
$payload = $match[2];
|
||||||
|
|
||||||
preg_match("/alg='(.*?)'/ism", $attributes, $matches);
|
preg_match("/alg='(.*?)'/ism", $attributes, $matches);
|
||||||
$algorithm = $matches[1] ?? '';
|
$algorithm = $matches[1] ?? '';
|
||||||
|
|
||||||
if ($matches[1] != "") {
|
if (!$algorithm) {
|
||||||
$algorithm = $matches[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
||||||
if ($matches[1] != "") {
|
$algorithm = $matches[1] ?? '';
|
||||||
$algorithm = $matches[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$algorithm) {
|
||||||
preg_match("/alg=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
preg_match("/alg=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
||||||
if ($matches[1] != "") {
|
$algorithm = $matches[1] ?? '';
|
||||||
$algorithm = $matches[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$matches = [];
|
$matches = [];
|
||||||
|
|
||||||
preg_match("/hint='(.*?)'/ism", $attributes, $matches);
|
preg_match("/hint='(.*?)'/ism", $attributes, $matches);
|
||||||
$hint = $matches[1] ?? '';
|
$hint = $matches[1] ?? '';
|
||||||
|
|
||||||
|
if (!$hint) {
|
||||||
preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
||||||
if ($matches[1] != "") {
|
$hint = $matches[1] ?? '';
|
||||||
$hint = $matches[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$hint) {
|
||||||
preg_match("/hint=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
preg_match("/hint=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
||||||
if ($matches[1] != "") {
|
$hint = $matches[1] ?? '';
|
||||||
$hint = $matches[1];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$x = random_string();
|
$x = random_string(32);
|
||||||
|
|
||||||
$f = 'sodium_decrypt';
|
$onclick = 'onclick="sodium_decrypt(\'' . $payload . '\',\'#' . $x . '\');"';
|
||||||
|
|
||||||
if (in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) {
|
if (in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) {
|
||||||
$f = 'hz_decrypt'; // deprecated
|
// backwards compatibility
|
||||||
|
$onclick = 'onclick="hz_decrypt(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $payload . '\',\'#' . $x . '\');"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$onclick = 'onclick="' . $f . '(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');"';
|
|
||||||
$label = t('Encrypted content');
|
$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><br>' . bb_parse_b64_crypt($match);
|
$Text = '<br><div id="' . $x . '"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div><br><br>' . bb_parse_b64_crypt($match);
|
||||||
|
@ -336,14 +337,9 @@ function bb_parse_crypt($match)
|
||||||
*/
|
*/
|
||||||
function bb_parse_b64_crypt($match)
|
function bb_parse_b64_crypt($match)
|
||||||
{
|
{
|
||||||
|
$r = '-----BEGIN ENCRYPTED MESSAGE-----' . "\n";
|
||||||
if (empty($match[2])) {
|
$r .= base64_encode($match[1]) . (($match[2]) ? "." . $match[2] : '') . "\n";
|
||||||
return;
|
$r .= '-----END ENCRYPTED MESSAGE-----' . "\n";
|
||||||
}
|
|
||||||
|
|
||||||
$r = '----- ENCRYPTED CONTENT -----' . "\n";
|
|
||||||
$r .= base64_encode($match[1]) . "." . $match[2] . "\n";
|
|
||||||
$r .= '----- END ENCRYPTED CONTENT -----' . "\n";
|
|
||||||
|
|
||||||
$r = '<code>' . str_replace("\n", '<br>', wordwrap($r, 75, "\n", true)) . '</code>';
|
$r = '<code>' . str_replace("\n", '<br>', wordwrap($r, 75, "\n", true)) . '</code>';
|
||||||
|
|
||||||
|
@ -2105,6 +2101,7 @@ function bbcode($Text, $options = [])
|
||||||
if ($activitypub) {
|
if ($activitypub) {
|
||||||
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_b64_crypt', $Text);
|
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_b64_crypt', $Text);
|
||||||
} else {
|
} else {
|
||||||
|
$Text = preg_replace_callback("/\[crypt\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
|
||||||
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
|
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
tests/unit/Web/BrowserEncryptionTest.php
Normal file
17
tests/unit/Web/BrowserEncryptionTest.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Code\Tests\Unit\Web;
|
||||||
|
|
||||||
|
class BrowserEncryptionTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testCryptParsing()
|
||||||
|
{
|
||||||
|
$encrypted = '[crypt]eyJoaW50IjoiNzQ2NTczNzQiLCJhbGciOiJYU2Fsc2EyMCIsInNhbHQiOiJmMmVlM2FiOTFmYzI0ZTdiODUxMmZhMWFjY2UwYjliNSIsIm5vbmNlIjoiMjllZGRlZDkwNTg2MDAxYjk3YTVlODc0MmQzNTVkZTdmZDQ1MTM0NWEyZTMyNWJlIiwiY2lwaGVydGV4dCI6Ijg3NjgwOWY0NDNlN2FjZDg3YTAxYTc5MGViNzIzMjI0NWI3NzRlN2QifQ==[/crypt]';
|
||||||
|
$encrypted2 = '[crypt]eyJoaW50IjoiNzQ2NTczNzQiLCJhbGciOiJYU2Fsc2EyMCIsInNhbHQiOiI1NWZhYmI4MTgyNGJmYWQ2MDU4NTM4YmZiZWNkNTMyOSIsIm5vbmNlIjoiNzkyNWQ5M2M4ZDU5MTZmNzlmN2UzZWFiMzI0MWJiMDY2Njc0MTM2OWI1OGZiMGE2IiwiY2lwaGVydGV4dCI6IjZmZGIwNDI1NzBjMTkwMTIwOTUzODIyYzNhZTA0YzA3ZjgwNDA2NGYifQ==[/crypt]';
|
||||||
|
|
||||||
|
$expected = '{"hint":"74657374","alg":"XSalsa20","salt":"f2ee3ab91fc24e7b8512fa1acce0b9b5","nonce":"29edded90586001b97a5e8742d355de7fd451345a2e325be","ciphertext":"876809f443e7acd87a01a790eb7232245b774e7d"}';
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,11 @@ async function sodium_encrypt(element) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = $(element).val();
|
let message = $(element).val();
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let password = prompt(aStr['passphrase']);
|
let password = prompt(aStr['passphrase']);
|
||||||
|
|
||||||
if (!password) {
|
if (!password) {
|
||||||
|
@ -40,6 +45,7 @@ async function sodium_encrypt(element) {
|
||||||
|
|
||||||
let salt = await sodium.randombytes_buf(16);
|
let salt = await sodium.randombytes_buf(16);
|
||||||
let nonce = await sodium.randombytes_buf(24);
|
let nonce = await sodium.randombytes_buf(24);
|
||||||
|
|
||||||
let key = await sodium.crypto_pwhash(
|
let key = await sodium.crypto_pwhash(
|
||||||
32,
|
32,
|
||||||
password,
|
password,
|
||||||
|
@ -52,31 +58,37 @@ async function sodium_encrypt(element) {
|
||||||
let ciphertext = await sodium.crypto_secretbox(message, nonce, key);
|
let ciphertext = await sodium.crypto_secretbox(message, nonce, key);
|
||||||
delete message, password, key;
|
delete message, password, key;
|
||||||
|
|
||||||
let s = await sodium.sodium_bin2hex(salt);
|
let payload = {
|
||||||
let n = await sodium.sodium_bin2hex(nonce);
|
hint: hint,
|
||||||
let c = await sodium.sodium_bin2hex(ciphertext);
|
alg: 'XSalsa20',
|
||||||
let encrypted = window.btoa(s + '.' + n + '.' + c);
|
salt: await sodium.sodium_bin2hex(salt),
|
||||||
let val = "[crypt alg='XSalsa20' hint='" + hint + "']" + encrypted + '[/crypt]';
|
nonce: await sodium.sodium_bin2hex(nonce),
|
||||||
|
ciphertext: await sodium.sodium_bin2hex(ciphertext)
|
||||||
|
};
|
||||||
|
|
||||||
|
let val = "[crypt]" + window.btoa(JSON.stringify(payload)) + '[/crypt]';
|
||||||
|
|
||||||
$(element).val(val);
|
$(element).val(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sodium_decrypt(alg, hint, encrypted, element) {
|
async function sodium_decrypt(payload, element) {
|
||||||
if (alg !== 'XSalsa20') {
|
let arr = JSON.parse(window.atob(payload));
|
||||||
|
|
||||||
|
if (arr.alg !== 'XSalsa20') {
|
||||||
alert('Unsupported algorithm');
|
alert('Unsupported algorithm');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let arr = window.atob(encrypted).split('.');
|
let password = prompt((arr.hint.length) ? hex2bin(arr.hint) : aStr['passphrase']);
|
||||||
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) {
|
if (!password) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let salt = await sodium.sodium_hex2bin(arr.salt);
|
||||||
|
let nonce = await sodium.sodium_hex2bin(arr.nonce);
|
||||||
|
let ciphertext = await sodium.sodium_hex2bin(arr.ciphertext);
|
||||||
|
|
||||||
let key = await sodium.crypto_pwhash(
|
let key = await sodium.crypto_pwhash(
|
||||||
32,
|
32,
|
||||||
password,
|
password,
|
||||||
|
@ -89,7 +101,7 @@ async function sodium_decrypt(alg, hint, encrypted, element) {
|
||||||
delete password, key;
|
delete password, key;
|
||||||
|
|
||||||
if ($(element).css('display') === 'none' && typeof tinyMCE !== typeof undefined) {
|
if ($(element).css('display') === 'none' && typeof tinyMCE !== typeof undefined) {
|
||||||
tinyMCE.activeEditor.setContent(newdiv);
|
tinyMCE.activeEditor.setContent(decrypted.toString('utf-8'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$(element).html(decrypted.toString('utf-8'));
|
$(element).html(decrypted.toString('utf-8'));
|
||||||
|
|
Loading…
Reference in a new issue