3

First, I have read this article.

Second, I read this post on StackOverflow, and though it was relatively recent, most of the promising links are dead.

Third, someone recommended Crypto-JS to me, but that appears to be Node based, and therefore server-side.

Which has brought me to taking a look at the Stanford Javascript Crypto Library, which looks pretty good, except I am not in any way a cryptographer and am therefore unqualified at evaluating it.

I'm basically looking for an easy to implement client-side encryption library. It would be delivered over SSL, and it's main purpose is simply to encrypt data before it reaches the server, rather than upon arrival. It's just for a pet project/proof of concept, but I'd like to do things as close to correct as I can.

With all that said, is there such thing as trusted/easy-to-implement client side AES encryption, either as a jQuery Plugin (doubtful, the only one I could find provides RC4 encryption) or else plain old Javascript? Or is this a futile idea?

Community
  • 1
  • 1
Lucas Krupinski
  • 682
  • 5
  • 16
  • (1) One of the authors of SJCL is Dan Boneh, who is one of the world's leading experts in the field. His MOOC at [Coursera](https://www.coursera.org/learn/crypto) is worth doing if you have the time. (2) If you can use SSL to deliver the Javascript, then why do you need this code anyway? (3) The earlier question you referred to was closed because it was off-topic for this site. You are asking the same question, so I'm afraid your question is also off-topic. – r3mainer May 03 '17 at 00:13
  • 1) will take a look at that, thanks. 2) I can use SSL to deliver the code, but I don't want access to the data that gets returned. Would rather the client encrypt it and return it in that form. 3) apologies - can you recommend a better venue? :) – Lucas Krupinski May 03 '17 at 00:45
  • (1) I can recommend it :-D (2) But AES is symmetric. If your server provides the encryption code and encryption key, then it can access the returned data. Wouldn't you be better off using asymmetric encryption (RSA) instead? (3) Maybe reddit can help (/r/crypto) – r3mainer May 03 '17 at 10:04
  • 2) I only want to use the SSL connection to deliver the code to the client, and leave it on them to create their own key/password before returning data to the server. But anyways, i'm apparently off topic (understandable, as there isn't a single line of code in my post), so I'm going to close this one. – Lucas Krupinski May 03 '17 at 11:33

2 Answers2

2

Etienne Martin is mostly right.

The only way you should be doing any crypto in browser if you have a choice is WebCrypto, it is pretty well supported by user agents now.

But if you need to to work on an older browser like IE you can use - https://github.com/PeculiarVentures/webcrypto-liner and your Webcrypto based code will work just fine.

Also be sure to use AES-GCM, it is an authenticated mode of AES and is the right thing to use.

What you want will look like:

function stringToArrayBuffer(str) {
    var buf = new ArrayBuffer(str.length);
    var bufView = new Uint8Array(buf);
    for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

function arrayBufferToString(str) {
    var byteArray = new Uint8Array(str);
    var byteString = '';
    for (var i = 0; i < byteArray.byteLength; i++) {
        byteString += String.fromCodePoint(byteArray[i]);
    }
    return byteString;
}

var text = "I am clear text";
console.log("what we will encrypt:");
console.log(text);

var data = stringToArrayBuffer(text);
console.log("what we encode to:");
console.log(data);

window.crypto.subtle.generateKey({
            name: "AES-GCM",
            length: 256, //can be  128, 192, or 256
        },
        false, //whether the key is extractable (i.e. can be used in exportKey)
        ["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey"
    )
    .then(function(key) {
        //returns a key object
        console.log("our key:");
        console.log(key);

        window.crypto.subtle.encrypt({
                    name: "AES-GCM",
                    //Don't re-use initialization vectors!
                    //Always generate a new iv every time your encrypt!
                    iv: window.crypto.getRandomValues(new Uint8Array(16)),
                },
                key, //from generateKey or importKey above
                data //ArrayBuffer of data you want to encrypt
            )
            .then(function(encrypted) {
                //returns an ArrayBuffer containing the encrypted data
                console.log("our ciphertext:");
                console.log(new Uint8Array(encrypted));
            })
            .catch(function(err) {
                console.error(err);
            });
    })
    .catch(function(err) {
        console.error(err);
    });
rmhrisk
  • 1,814
  • 10
  • 16
  • That is awesome, didn't know about webcrypto-liner, thanks Ryan! – Etienne Martin May 04 '17 at 12:50
  • 1
    In full disclosure its one of my libraries, but it does the trick. You can even do isomorphic code on node using https://github.com/PeculiarVentures/node-webcrypto-ossl or https://github.com/PeculiarVentures/node-webcrypto-p11 – rmhrisk May 04 '17 at 15:40
1

I recommend the new WebCrypto API, the next generation standard from the W3C.

It's now supported by all major browsers out of the box. It's pretty easy to use and has really good performance compared with any other JS-based solutions.

Here are the main advantages I can think of:

  • No external library (Shipped with the browser)
  • Asynchronous (Doesn't block the UI)
  • Multithreaded
  • Hardware accelerated
  • Near-native performance (10x faster than traditional crypto libraries)
  • Cryptographically secure number generator (It provides direct access to the system’s secure random number generator)

See @rmhrisk's answer for older browser support.

Here's an example of how to encrypt using the WebCrypto API: https://github.com/diafygi/webcrypto-examples#aes-gcm---encrypt

Community
  • 1
  • 1
Etienne Martin
  • 10,018
  • 3
  • 35
  • 47