Charles Engelke's Blog

July 5, 2014

Symmetric Cryptography in the Browser – Part 2

Filed under: Uncategorized — Charles Engelke @ 12:31 pm
Tags: ,

This post is part of a series on cryptography in the browser. My last post covered the basics of encrypting and decrypting with the Web Cryptography API, but had no practical use. That’s because you couldn’t save and later load the key you used, and you couldn’t get meaningful amounts of data into and out of the software. We’ll address the first of those needs now. When we created our encryption key we set the exportable parameter to true. If we hadn’t, the actual key would forever be hidden from us, which would be a good idea if there were an outside-the-browser way to manage it. As of now, there isn’t such a way, so we’ll manage keys in the browser. That requires exporting them to a format that can be saved and transported and importing them from those formats. The format we’ll use is a hexadecimal string, so our 128 bit (16 byte) key will be a 32 character string. We can export a key to a byte array using the window.crypto.subtle.exportKey method. This is a pretty easy method to use. It takes two parameters: the format you want to export to, and the key to export. It returns a promise that passes the exported key (as an ArrayBuffer) to its then method’s parameter. Assuming our AES key is in the variable aesKey, here’s how to get it into a viewable form:

var aesKeyBytes;

window.crypto.subtle.exportKey('raw', aesKey).
then(function(result) {aesKeyBytes = new Uint8Array(result);}).
catch(function(err) {alert("Something went wrong: " + err.message);});

When I try that in my browser with a defined aesKey, I get the following bytes: [51, 155, 145, 34, 55, 159, 162, 158, 253, 202, 19, 78, 139, 186, 51, 118] So I can see the actual key, but I’d rather look at it in hex. For example, 51 is 33 in hex, 155 is 9b, 145 is 91, and so on. I can convert a Uint8ByteArray to a hexadecimal string by converting each byte and concatenating them:

function byteArrayToHexString(byteArray) {
    var hexString = '';
    var nextHexByte;
    for (var i=0; i<byteArray.byteLength; i++) {
        nextHexByte = byteArray[i].toString(16);  // Integer to base 16
        if (nextHexByte.length < 2) {
            nextHexByte = "0" + nextHexByte;     // Otherwise 10 becomes just a instead of 0a
        }
        hexString += nextHexByte;
    }
    return hexString;
}

Given the aesKey and aesKeyBytes shown above, byteArrayToHexString(aesKeyBytes) returns "339b9122379fa29efdca134e8bba3376", which I can easily display and save. Going the other way is pretty easy now. We will use the window.crypto.subtle.importKey method, after first converting a hex string to a byte array with this function:

function hexStringToByteArray(hexString) {
    if (hexString.length % 2 !== 0) {
        throw "Must have an even number of hex digits to convert to bytes";
    }
    var numBytes = hexString.length / 2;
    var byteArray = new Uint8Array(numBytes);
    for (var i=0; i<numBytes; i++) {
        byteArray[i] = parseInt(hexString.substr(i*2, 2), 16);
    }
    return byteArray;
}

Trying it out, hexStringToByteArray("339b9122379fa29efdca134e8bba3376") returns [51, 155, 145, 34, 55, 159, 162, 158, 253, 202, 19, 78, 139, 186, 51, 118], which is what I started with. Now that we have the array of bytes, we’re ready to import it to create a key. The importKey method takes all the same parameters as createKey, plus the key’s bytes and format of those bytes, so the steps to use them are almost the same:

var importedAesKey;

window.crypto.subtle.importKey(
    "raw",                          // Exported key format
    aesKeyBytes,                    // The exported key
    {name: "AES-CBC", length: 128}, // Algorithm the key will be used with
    true,                           // Can extract key value to binary string
    ["encrypt", "decrypt"]          // Use for these operations
).
then(function(key) {importedAesKey = key;}).
catch(function(err) {alert("Something went wrong: " + err.message);});

Now that we can get keys in and out of our code in a human readable form, we’re ready to actually encrypt and decrypt files. The next post will encrypt or decrypt a File into a Blob that can be downloaded. Then we’ll put it all together into a complete web page that performs all these functions.

Advertisements

2 Comments

  1. […] couple of utility functions to convert between hex encoded strings and arrays of bytes. We saw them two posts ago, but here they are again for […]

    Pingback by Symmetric Cryptography in the Browser – Conclusion | Charles Engelke's Blog — July 16, 2014 @ 8:36 pm

  2. […] been a month since I published posts on how to perform symmetric cryptography in web browsers using the Web Cryptography API. Now we’ll move on […]

    Pingback by Public Key Cryptography in the Browser | Charles Engelke's Blog — August 23, 2014 @ 11:08 am


RSS feed for comments on this post.

Create a free website or blog at WordPress.com.

%d bloggers like this: