// Artur Mustafin, (c) 2019 // Park & Miller, (c) 1988,1993 const default_alphabet = [ 'A','B','C','D','E','F', 'G','H','I','J','K','L', 'M','N','O','P','Q','R', 'S','T','U','V','W','X', 'Y','Z',' ',':',',','*', '~','!','@','#','%','^', '-','=','0','1','2','3', '4','5','6','7','8','9', 'a','b','c','d','e','f', 'g','h','i','j','k','l', 'm','n','o','p','q','r', 's','t','u','v','w','x', 'y','z','"','?','.','_', '+','(',')','[',']','|', '{','}','`','\/' //88 ]; let alphabet = default_alphabet; // LCG Park & Miller (c) 1988,1993 (original value proposed was 16807, in 1993 changed to 48271) // s=>()=>(2**31-1&(s=Math.imul(48271,s)))/2**31 var PRNG = function(seed){ this._seed = seed % 2147483647; if (this._seed <= 0){ this._seed += 2147483646;} }; PRNG.prototype.next = function(a,b){ this._seed = this._seed * 48271 % 2147483647; // in response to a criticism by Marsaglia in 1993 if(arguments.length === 0){ return this._seed/2147483647; }else if(arguments.length === 1){ return (this._seed/2147483647)*a; }else{ return (this._seed/2147483647)*(b-a)+a; } }; var seed = 1238473661; var rnd = new PRNG(seed); var random = 0; var maximus = 2147483647 >> 2; var enc_offset = 0; var dec_offset = 0; Array.prototype.shuffle = function(seed) { return shuffle(this, seed); } Array.prototype.unshuffle = function(seed) { return unshuffle(this, seed); } Array.prototype.offset = function(seed) { return offset(this, seed); } Array.prototype.unoffset = function(seed) { return unoffset(this, seed); } function shuffle(array, seed) { let rng = new PRNG(seed); for (let i = array.length - 1; i > 0; i--) { let j = Math.floor(rng.next(i));// Math.random() * (i + 1)); // random index from 0 to i [array[i], array[j]] = [array[j], array[i]]; // swap elements } return array; } function unshuffle(array, seed) { let indexes = []; let rng = new PRNG(seed); for (let i = array.length - 1; i > 0; i--) { let j = Math.floor(rng.next(i)); indexes.push(j); } for (let i = 1; i < array.length; i++) { let j = indexes.pop(); //Math.floor(rng.next(i));// Math.random() * (i + 1)); // random index from 0 to i [array[i], array[j]] = [array[j], array[i]]; // swap elements } return array; } function offset(array, offset) { let length = array.length; for (let i = length - 1; i > 0; i--) { let j = (2*maximus + i + offset)%length; [array[i], array[j]] = [array[j], array[i]]; // swap elements } return array; } function unoffset(array, offset) { let length = array.length; let indexes = []; for (let i = length - 1; i > 0; i--) { let j = (2*maximus + i + offset)%length; indexes.push(j); } for (let i = 1; i < length; i++) { let j = indexes.pop(); [array[i], array[j]] = [array[j], array[i]]; // swap elements } return array; } function randomInteger(min, max) { let rand = min + rnd.next() * (max + 1 - min); return Math.floor(rand); } const cipher_size = alphabet.length; const encrypt = document.getElementById('encrypt'); const decrypt = document.getElementById('decrypt'); const plaintext1 = document.getElementById('plaintext1'); const plaintext2 = document.getElementById('plaintext2'); const output1 = document.getElementById('output1'); const output2 = document.getElementById('output2'); const IV1 = document.getElementById('IV1'); const IV2 = document.getElementById('IV2'); const alpha1 = document.getElementById('alphabet1'); const alpha2 = document.getElementById('alphabet2'); const app = document.getElementById('apply'); const randomize = document.getElementById('randomize'); const alphabet_random = document.getElementById('alphabet_random'); this.random = randomInteger(0,maximus); IV1.value = this.random; randomize.addEventListener ('click',event => { event.preventDefault(); this.random = randomInteger(0,maximus); this.IV1.value = this.random; }); alphabet_random.addEventListener ('click',event => { event.preventDefault(); alphabet = default_alphabet; alphabet.shuffle(this.random); alpha1.value = alphabet.join(''); }); encrypt.addEventListener ('click',event => { event.preventDefault(); this.random = parseInt(this.IV1.value); alphabet = [... alpha1.value]; this.enc_offset = this.random; const shift = Number(shift1.value); let array = [... plaintext1.value ]; for(let i=0; i< shift; i++) array = array.shuffle(this.random).map(char => shift_encrypt(char, shift)); output1.value = array.offset(this.random).join(''); } ); app.addEventListener ('click',event => { event.preventDefault(); this.IV2.value = this.IV1.value; shift2.value = shift1.value; alpha2.value = alpha1.value; plaintext2.value = output1.value; output2.value = ''; }); decrypt.addEventListener ('click',event => { event.preventDefault(); this.random = parseInt(this.IV2.value); alphabet = [... alpha2.value]; this.dec_offset = parseInt(this.IV2.value); const shift = Number(shift2.value); let array = [... plaintext2.value ].unoffset(this.random); for(let i=0; i< shift; i++) array = array.map(char => shift_decrypt(char, shift)).unshuffle(this.random); output2.value = array.join(''); } ); function shift_encrypt(char, shift) { if (shift%2 == 1) { char = _encrypt(_encrypt(char,alphabet,shift),alphabet,shift); } else { char = _encrypt(_encrypt(char,alphabet.reverse(),0),alphabet.reverse(),0); } return char; } function shift_decrypt(char, shift) { if (shift%2 == 1) { char = _decrypt(_decrypt(char,alphabet,shift),alphabet,shift); } else { char = _decrypt(_decrypt(char,alphabet.reverse(),0),alphabet.reverse(),0); } return char; } function _encrypt(char, alphabet, shift) { if (alphabet.includes(char)) { const position = alphabet.indexOf(char); const newPosition = (2*maximus - position + this.enc_offset - shift)%cipher_size; this.enc_offset = (++this.enc_offset)%cipher_size; return alphabet[newPosition] } else { return char } } function _decrypt(char, alphabet, shift) { if (alphabet.includes(char)) { const position = alphabet.indexOf(char); const newPosition = (2*maximus - position - this.dec_offset - shift)%cipher_size; this.dec_offset = (++this.dec_offset)%cipher_size; return alphabet[newPosition] } else { return char } }