Decode a Base64 String using CryptoJS

aliasbody picture aliasbody · Aug 25, 2014 · Viewed 46.2k times · Source

I am trying to create a simple webpage with the goal to send and encrypted message to the server (which will create a file with that content), then a link is created and the user who receive the link provided will be able to see the encrypted value (since it provides the name of the file and the key).

The message is encrypted using CryptoJS AES, and the result is Base64 encoded to be decoded after that, only the Base64 of the encrypted message and the encrypted message is sent to the server nothing else, and this is done using Javascript.

My question here is. I have a message, let say "Hello World" which I encode using Base64, and it gives me this :

1ffffffff5a8ae57

If I send this value to a variable, and then just use that variable, it show a result :

// Works !
var test = CryptoJS.enc.Base64.parse("Hello World");
alert(CryptoJS.enc.Base64.stringify(test));

Which is normal. But If I try to write directly the text (or just do a toString(), it doesn't work... which is also normal because the 'test' variable isn't a simple String variable) :

// Doesn't work !
var test = CryptoJS.enc.Base64.parse("Hello World").toString();
alert(CryptoJS.enc.Base64.stringify(test));

But I need to use a String since it is based on a PHP $_GET Value which is then decoded using Javascript again. So my question is, how can I do this in order to encode a String and then decoded the result as a String ?

This is my engine.js file :

// Encrypt the message using a generated key
function encrypt(message, key) {
    return CryptoJS.AES.encrypt(message, key);
}

// Encode String to Base64
function encodeBase64(value) {
    return CryptoJS.enc.Base64.parse(value.toString());
}

// Decode String from Base64 Enconding
function decodeBase64(encodedValue) {
    return CryptoJS.enc.Base64.stringify(encodedValue);
}

// Decrypt the message using the generated key
function decrypt(encrypted, key) {
    return CryptoJS.AES.decrypt(encrypted, key).toString(CryptoJS.enc.Utf8);
}

// Generate the random key
function generateKey() {
    return CryptoJS.lib.WordArray.random(16).toString();
}

// Generate the random fileName
function generateFileName() {
    return CryptoJS.lib.WordArray.random(16).toString();
}

// Convert the text on the form with the encrypted version to be sent into the server
function SendMessage(message, FinalURL) {
    if ((message.value).trim()) {
        var xmlhttp = new XMLHttpRequest;
        xmlhttp.open("POST", "index.php", true);
        xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

        // Generate the Key and Encrypt the Message
        var key             = generateKey();
        var encryptedData   = encrypt(message.value, key);
        var fileName        = generateFileName();      

        xmlhttp.send("fileName=" + fileName + "&encryptedMsg=" + encodeBase64(encryptedData));

        var finalURL = document.URL + "?MessageID=" + fileName + "&Key=" + key;

        FinalURL.innerHTML = "<p>Final URL: <a href=" + finalURL + ">" + finalURL + "</a></p>";
    } else {
        alert("There is no text to be encrypted !");
    }
}

Answer

decates picture decates · Dec 30, 2014

I ran into a similar confusion, and for reference, here is the solution.

To turn a text string (UTF-8 encoded) into a base-64 string, you need:

var textString = 'Hello world'; // Utf8-encoded string
var words = CryptoJS.enc.Utf8.parse(textString); // WordArray object
var base64 = CryptoJS.enc.Base64.stringify(words); // string: 'SGVsbG8gd29ybGQ='

To turn a base-64 encoded string back into text (UTF-8 encoded), it's:

var base64 = 'SGVsbG8gd29ybGQ=';
var words = CryptoJS.enc.Base64.parse(base64);
var textString = CryptoJS.enc.Utf8.stringify(words); // 'Hello world'

Some explanation

As you can see from the examples given in the CryptoJS documentation, parse is meant to parse a string in the format that the encoder is expecting (into a WordArray), and stringify turns a WordArray into a string.

From the documentation:

var words  = CryptoJS.enc.Base64.parse('SGVsbG8sIFdvcmxkIQ==');
var base64 = CryptoJS.enc.Base64.stringify(words); // 'Hello, World!'

The WordArray is CryptoJS's format-independent representation of data. Formatters (like Base64 and Utf8) are interfaces between this WordArray format, and strings, which may contain data encoded in any format. So to change between formats, you need a formatter at either end, one parsing and one stringifying (i.e. encoding). In this case, you need to remember that when we write 'Hello World', that's text encoded in a particular format (I'm assuming UTF-8).

I found this Gist helpful.