mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-20 04:35:26 +00:00
221 lines
5.7 KiB
JavaScript
221 lines
5.7 KiB
JavaScript
function str_rot13 (str) {
|
|
// http://kevin.vanzonneveld.net
|
|
// + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
|
|
// + improved by: Ates Goral (http://magnetiq.com)
|
|
// + bugfixed by: Onno Marsman
|
|
// + improved by: Rafa? Kukawski (http://blog.kukawski.pl)
|
|
// * example 1: str_rot13('Kevin van Zonneveld');
|
|
// * returns 1: 'Xriva ina Mbaariryq'
|
|
// * example 2: str_rot13('Xriva ina Mbaariryq');
|
|
// * returns 2: 'Kevin van Zonneveld'
|
|
// * example 3: str_rot13(33);
|
|
// * returns 3: '33'
|
|
return (str + '').replace(/[a-z]/gi, function (s) {
|
|
return String.fromCharCode(s.charCodeAt(0) + (s.toLowerCase() < 'n' ? 13 : -13));
|
|
});
|
|
}
|
|
|
|
// Arrays for pluggable encryptors/decryptors
|
|
|
|
let red_encryptors = new Array();
|
|
let red_decryptors = new Array();
|
|
|
|
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();
|
|
|
|
if (!message) {
|
|
return false;
|
|
}
|
|
|
|
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 payload = {
|
|
hint: hint,
|
|
alg: 'XSalsa20',
|
|
salt: await sodium.sodium_bin2hex(salt),
|
|
nonce: await sodium.sodium_bin2hex(nonce),
|
|
ciphertext: await sodium.sodium_bin2hex(ciphertext)
|
|
};
|
|
|
|
let val = "[crypt]" + window.btoa(JSON.stringify(payload)) + '[/crypt]';
|
|
|
|
$(element).val(val);
|
|
}
|
|
|
|
async function sodium_decrypt(payload, element) {
|
|
let arr = JSON.parse(window.atob(payload));
|
|
|
|
if (arr.alg !== 'XSalsa20') {
|
|
alert('Unsupported algorithm');
|
|
return false;
|
|
}
|
|
|
|
let password = prompt((arr.hint.length) ? hex2bin(arr.hint) : aStr['passphrase']);
|
|
|
|
if (!password) {
|
|
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(
|
|
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(decrypted.toString('utf-8'));
|
|
}
|
|
else {
|
|
$(element).html(decrypted.toString('utf-8'));
|
|
}
|
|
}
|
|
|
|
|
|
function hz_encrypt(alg, elem) {
|
|
var enc_text = '';
|
|
var newdiv = '';
|
|
|
|
if(typeof tinyMCE !== "undefined")
|
|
tinyMCE.triggerSave(false,true);
|
|
|
|
var text = $(elem).val();
|
|
|
|
// key and hint need to be localised
|
|
|
|
var passphrase = prompt(aStr['passphrase']);
|
|
// let the user cancel this dialogue
|
|
if (passphrase == null)
|
|
return false;
|
|
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.
|
|
|
|
if(! enc_key)
|
|
alg = 'rot13';
|
|
|
|
if((alg == 'rot13') || (alg == 'triple-rot13'))
|
|
newdiv = "[crypt alg='rot13']" + window.btoa(str_rot13(text)) + '[/crypt]';
|
|
|
|
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.
|
|
|
|
var enc_hint = bin2hex(prompt(aStr['passhint']));
|
|
|
|
enc_text = sjcl.encrypt(enc_key, text);
|
|
|
|
encrypted = enc_text.toString();
|
|
|
|
newdiv = "[crypt alg='AES-128-CCM' hint='" + enc_hint + "']" + window.btoa(encrypted) + '[/crypt]';
|
|
}
|
|
|
|
if((red_encryptors.length) && (! newdiv.length)) {
|
|
for(var i = 0; i < red_encryptors.length; i ++) {
|
|
newdiv = red_encryptors[i](alg,text);
|
|
if(newdiv.length)
|
|
break;
|
|
}
|
|
}
|
|
|
|
enc_key = '';
|
|
|
|
// This might be a comment box on a page with a tinymce editor
|
|
// so check if there is a tinymce editor but also check the display
|
|
// 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);
|
|
}
|
|
else {
|
|
$(elem).val(newdiv);
|
|
}
|
|
|
|
}
|
|
|
|
function hz_decrypt(alg, hint, text, elem) {
|
|
|
|
var dec_text = '';
|
|
|
|
text = window.atob(text);
|
|
|
|
if(alg == 'rot13' || alg == 'triple-rot13')
|
|
dec_text = str_rot13(text);
|
|
else {
|
|
var enc_key = bin2hex(prompt((hint.length) ? hex2bin(hint) : aStr['passphrase']));
|
|
}
|
|
|
|
if(alg == 'AES-128-CCM') {
|
|
dec_text = sjcl.decrypt(enc_key, text);
|
|
}
|
|
|
|
if((red_decryptors.length) && (! dec_text.length)) {
|
|
for(var i = 0; i < red_decryptors.length; i ++) {
|
|
dec_text = red_decryptors[i](alg,text,enc_key);
|
|
if(dec_text.length)
|
|
break;
|
|
}
|
|
}
|
|
|
|
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
|
|
// 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.
|
|
|
|
var dec_result = dec_text.toString();
|
|
delete dec_text;
|
|
|
|
// incorrect decryptions *usually* but don't always have zero length
|
|
// If the person typo'd let them try again without reloading the page
|
|
// otherwise they'll have no "padlock" to click to try again.
|
|
|
|
if(dec_result.length) {
|
|
$(elem).html(b2h(dec_result));
|
|
dec_result = '';
|
|
}
|
|
}
|
|
|