I am writing browser javascript that has a pre-shared key with nonce, and creates a binary websocket connection. How can I apply block encryption-authentication such as AES-GCM to the messages?

Is it possible to tell the browser to skip the PKI handshake on wss://, or do I have to actually import a javascript cipher package? (If the latter, what is the performance like?)

(If the solution involves providing a certificate explicitly in the client WebSocket object, then we also need to be sure that it works with multiple users that don't trust one another. In other words, we'd need a way for the client to tell the server which certificate to use. I am not aware of such a mechanism in SSL, so I'm guessing that PKI needs to be bypassed entirely.)

1 Answer 1


SubtleCrypto (what a name!) is available in most browsers since 2015:


Note that it is only available in secure contexts (file:// and https://).

Here is a simple usage example (works in Chrome 66 and Firefox 88):

<html><head><meta charset="utf-8"></head><body><script>

let name = "AES-GCM";
let uses = ['encrypt','decrypt'];
let key  = [ 2017003337, 2151884619, 3312622559, 2426676393,
             1716639861, 1783909318, 1157370473, 2461016473 ]

key = new Uint32Array(key).buffer;
crypto.subtle.importKey('raw', key, {name}, true, uses).then(key => {

  let iv   = new Uint32Array([123456789, 987654321, 55555555]);
  let src  = new TextEncoder().encode("hello, world!");
  crypto.subtle.encrypt({name, iv}, key, src).then(e => {
    console.log(new Uint8Array(e));

    // uncomment to inject an error
    //(new Uint8Array(e))[0] = 1;

    crypto.subtle.decrypt({name, iv}, key, e).then(d => {
      console.log(new TextDecoder().decode(d));



Unfortunately it is asynchronous (i.e., generates a new event pass). However, I'm guessing it still executes faster than a direct Javascript implementation of AES-GCM.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .