DEV Community

Richard Leddy
Richard Leddy

Posted on

Crypto-wraps

So, I put this npm package out there: crypto-wraps

For this package, which is on GitHub crypto-wraps-GitHub

npm test
Enter fullscreen mode Exit fullscreen mode

I tested it in FireFox and node.js

As with many wrapper libraries, some of the methods pick which encryption standard they use. So, while crypto.subtle gives you just about every standard crypto routine you can think of, this library just uses some of them.

More on the crypto.subtle library can be found at MDN: Crypto/subtle.

What is there to say? Well, calling the crypto.subtle methods has its ins and outs. The code gets a little long, and you are always worrying about the types of the data buffers going in and out of the methods. Then, since the crypto.subtle methods always use ArrayBuffers or more specifically Uint8Arrays, your program has to put the buffers into text (hex or base64url) to send them anywhere.

Actually, I ran into some trouble storing buffers straight up in the IndexedDB. But, they stored well as blobURls which are usually a base64 encoding of the blob along with some mime type information. But, yes, the first time I stuck a blob straight into the IndexedDB to have it disappear, I was a little surprised and started converting the buffers to base text.

So, here is a code example from the node.js test:

let cwraps = require('../lib/crypto-wraps')
let hashit = require('../lib/crypto-hash');
...

    let again_text = "Finally the last test again until the next last test."
    let again_cipher_text = await cwraps.encipher_message(again_text,aes_key,nonce)
    let wrapped_key = await cwraps.key_wrapper(aes_key,key_pack.pk_str)
    let again_decipher_text =  await cwraps.decipher_message(again_cipher_text,wrapped_key,key_pack.priv_key,nonce)

Enter fullscreen mode Exit fullscreen mode

Now, I saved myself a lot lines. Here is the code for just the key_wrapper:

async function key_wrapper(key_to_wrap,pub_wrapper_key) {
    try {
        let wrapper_jwk = JSON.parse(pub_wrapper_key)
        let wrapper = await g_crypto.importKey(
                "jwk",
                wrapper_jwk,
                {   //these are the wrapping key's algorithm options
                    name: "RSA-OAEP",
                    modulusLength: 4096, //can be 1024, 2048, or 4096
                    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
                    hash: { name: "SHA-256" },
                },
                true,
                ["wrapKey"]
        );

        let wrapped_key = await g_crypto.wrapKey(
                                            "jwk",
                                            key_to_wrap,
                                            wrapper,
                                            {   //these are the wrapping key's algorithm options
                                                name: "RSA-OAEP"
                                            }
                                        );
        let type8 = new Uint8Array(wrapped_key)
        let tranportable = to_base64_from_uint8array(type8)
        return tranportable
    } catch(e) {
        console.log(e)
    }
    return false
}
Enter fullscreen mode Exit fullscreen mode

So, you see how things can grow. Here the program is parsing JSON to get an "jwk" object carrying the public wrapper key. This is the key you would give someone to wrap something to send to you, that only you can unwrap with your private key. The code imports the wrapper key from the "jwk" object. The key to wrap is passed in as an object of type Cryptokey. The wrapper does not know too much about it. But, it is an AES key that I got out of the key gen method.

The methods are using this global variable: g_crypto. The reason for that is that node.js exposed the crypto.subtle methods from one global object, while the browser uses another:

node.js way:

let g_crypto = crypto.webcrypto.subtle
Enter fullscreen mode Exit fullscreen mode

browser way:

window.g_crypto = window.crypto ? window.crypto.subtle : null
Enter fullscreen mode Exit fullscreen mode

It turns out that node.js and the browser are very much in agreement with the exposition of the crypto.subtle methods. The modules, crypto-wraps.js, for the two versions are almost identical. For base64url encoding, they both import to methods from the hash module:

  • to_base64_from_uint8array
  • from_base64_to_uint8array

These methods do differ between node.js and the browser. But, at the next level up, they are used exactly the same.

For the browser version, I borrowed base64 encoding from a Gist by Egor Nepomnyaschih. base64. That proved to be very helpful. The node version makes use of easy Buffer class conversions.

That's all for now folks.

Have fun with it. Leave notes in the issues. Thanks.

Top comments (0)