JavaScript Ninja – String Encryption, Easily!

  • Keeping some data in your JavaScript source, is unavoidable,
    it is best to keep it at-least, somewhat obfuscated.
  • Here is a simple string encrypt/decrypt function.
  • First run the function with your plain-text, to encrypt it.
    Next, store both the function and the encrypted text in your source-code.
    Need the plain-text again?
    Run the function again, but this time: on your encrypted text!
    to get the plain-text back.
  • The function is added to the String prototype for an easy access.
  • The Code:

    String.prototype.normalise_to_ascii   = function(){return unescape(encodeURIComponent(this)); }
    String.prototype.normalise_to_unicode = function(){return decodeURIComponent(escape(this));   }
    
    String.prototype.crypt_symmetric = function(key){
      var me = this + "";                                             //unlink reference
    
      key = Number(String(Number(key))) === key ? Number(key) : 13;   //optionaly provide key for symmetric-like-""encryption"".
    
      me = me.split('')                                               //to array of characters.
             .map(function(c){return c.charCodeAt(0);})               //to array of numbers (each is character's ASCII value)
             .map(function(i){return i ^ key;        })               //XOR ""ENCRYPTION""
             ;
      me = String.fromCharCode.apply(undefined, me);                  //one-liner trick: array-of-numbers to array-of-characters (ASCII value), join to single string. may result in buffer-overflow on long string!
      return me;
    };
    
  • Examples:

    • "hello".crypt_symmetric();
      will result with ehaab.
    • "שָלוֹם".crypt_symmetric();
      will result with פֵבטִא.

    Optionally keep your characters in the ASCII range,
    by .normalise_to_ascii() and bring them back
    to Unicode using .normalise_to_unicode().

    The explanation “why it is required?” is a bit long,
    so it is up to you if it is needed or not.

    Basically, since XOR creates a little character-shift,
    You might end up with a “control-character”, that might make your code looks ugly,
    at this case you can always use "YOUR_STRING".crypt_symmetric().normalise_to_ascii() and btoa,
    to keep it as a BASE64 string,
    followed by atob and "YOUR_STRING".normalise_to_unicode().crypt_symmetric() to restore it :]

  • Yes. The same function acts as an ecryptor and as a decryptor.
    It uses a very simple symmetric-encryption using XOR and a key,
    which by default is 13, but you may, optionally, provide your own key (number).
  • You are provided with some-what longer function,
    to help you visualise the steps, and simplified your understanding.
    Feel free to modify, minify the base structure to make it more/less complex to your needs… :]

    • Best to keep it simple though.

also available on this gist:
https://gist.github.com/eladkarako/738ff6791dd2e44baeb5787851f874d5


A slightly minified version of the same, as above..

String.prototype.norm_to_ascii=function(){return unescape(encodeURIComponent(this))};
String.prototype.norm_to_unicode=function(){return decodeURIComponent(escape(this))};
String.prototype.crypt_sym=function(k){return String.fromCharCode.apply(undefined,this.split("").map(function(c){return c.charCodeAt(0)^(k||13)}))};

//do this manually
btoa("password".norm_to_ascii().crypt_sym());
//get "fWx+fnpif2k="
//store "fWx+fnpif2k=" in your code along with those 3 functions above.
//
//when needed the value, run:
atob("fWx+fnpif2k=").norm_to_unicode().crypt_sym()
//get "password"
//....done....


How to use it as a bookmarklet (to put your password into the correct input-element, to save you some typing).

let us assume your password is: password,
now you can create a bookmarklet with the encrypted password, that will put the decrypted value, right inside the correct input-element, ready for you to press the next button.

first step is generate the password:

String.prototype.norm_to_ascii=function(){return unescape(encodeURIComponent(this))};
String.prototype.norm_to_unicode=function(){return decodeURIComponent(escape(this))};
String.prototype.crypt_sym=function(k){return String.fromCharCode.apply(undefined,this.split("").map(function(c){return c.charCodeAt(0)^(k||13)}))};

//do this manually
btoa("password".norm_to_ascii().crypt_sym(1111).norm_to_ascii());

we’ll get: fWx+fnpif2k=.

next is to make the minimalist, ad-hoc, bookmarklet:

javascript:(function(){top.document.querySelector('input[name="password"]').value=String.fromCharCode.apply(null,unescape(encodeURIComponent(atob("fWx+fnpif2k="))).split("").map(function(c){return c.charCodeAt(0)^13}));return true}());

You can me things more readable if you want to duplicate the same bookmarklet for other websites:

javascript:(function(e,v,k){e.value=String.fromCharCode.apply(null,unescape(encodeURIComponent(atob(v))).split("").map(function(c){return c.charCodeAt(0)^k}));return true;}(top.document.querySelector('input[name="password"]'),"fWx+fnpif2k=",13));

this way you can change the selector query, the encrypted password, and the key from “outside” the main function :]

Have Fun!