Vue

by lyquix

HTML

<div id="app">
  <div>
    <label for="password">Password</label><br>
    <input id="password" name="password" v-model="password">
  </div>
  <div>
    <label for="key">Key</label><br>
    <input id="key" name="key" v-model="key">
    <button id="randomKey" v-on:click="handleRandomButton">Random</button>
  </div>
  <div>
    <label for="plaintext">Plain Text</label><br>
    <textarea id="plaintext" name="plaintext" v-model="plaintext" rows="20"></textarea>
  </div>
  <div>
    <label for="cyphertext">Cypher Text</label><br>
    <textarea id="cyphertext" name="cyphertext" v-model="cyphertext" rows="20"></textarea>
  </div>
  <div>
    <label for="decryptedtext">Decrypted Text</label><br>
    <textarea id="decryptedtext" name="decryptedtext" v-model="decryptedtext" rows="20" readonly></textarea>
  </div>
</div>

CSS

body, * {
  font-family: sans-serif;
  box-sizing: boder-box;
  margin: 0;
}

div {
  margin: 1em 0;
}

#app {
  margin: 1em;
  max-width: 960px;
}

input, textarea {
  width: 100%;
  border-radius: 3px;
  border: 1px solid #999;
  padding: 5px 3px;
  font-family: monospace;
}

#key {
  max-width: calc(100% - 100px);
}

#randomKey {
  width: 87px;
  padding: 6px 3px;
  background: gray;
  color: white;
  text-transform: uppercase;
  border: none;
}

Vue

new Vue({
  el: "#app",
  data: {
  	password: '',
    key: '',
    plaintext: '',
    cyphertext: '',
    decryptedtext: ''
  },
  methods: {
  	handleRandomButton: function() {
    	this.password = this.randomStr();
    },
    
    encrypt: function(key, plaintext) {
      let cyphertext = [];
			// Convert to hex to properly handle UTF8
			plaintext = Array.from(plaintext).map(function(c) {
				if(c.charCodeAt(0) < 128) return c.charCodeAt(0).toString(16).padStart(2, '0');
				else return encodeURIComponent(c).replace(/\%/g,'').toLowerCase();
			}).join('');
			plaintext = plaintext.match(/.{1,2}/g).map(x => parseInt(x, 16));
			// Convert each hex to decimal
			for (let i = 0; i < plaintext.length; i++) {
				cyphertext.push(plaintext[i] ^ key.charCodeAt(Math.floor(i % key.length)));
			}
			cyphertext = cyphertext.map(function(x) {
        return x.toString(16).padStart(2, '0');
			});
			return cyphertext.join('');
    },

    // Super simple XOR decrypt function
    decrypt: function(key, cyphertext) {
      try {
  			cyphertext = cyphertext.match(/.{1,2}/g).map(x => parseInt(x, 16));
        let plaintext = [];
        for (let i = 0; i < cyphertext.length; i++) {
          plaintext.push((cyphertext[i] ^ key.charCodeAt(Math.floor(i % key.length))).toString(16).padStart(2, '0'));
        }
        return decodeURIComponent('%' + plaintext.join('').match(/.{1,2}/g).join('%'));    
      }
      catch(e) {
      	return '';
      }
    },

    // Super simple password to 256-bit key function
    passwordDerivedKey: function(password, salt, iterations, len) {
			if(!password) password = this.randomStr();
			if(!salt) salt = '80ymb4oZ';
			if(!iterations) iterations = 16;
			if(!len) len = 256;
      len = Math.ceil(len / 8);
			var key = '';

			while(key.length < len) {
				var i = 0;
				var intSalt = salt;
				var intKey = '';
				while(i < iterations) {
					intKey = this.hash(password + intSalt);
					var newSalt = '';
					for(let j = 0; j <...