The JavaScript Cryptography API That You May Have Missed
Tags: javascript, webdev, tutorial
Published: 2020-01-19 01:24:46

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

The `window` object is a global object that has that provides JavaScript access to the DOM. It also contains a standard library of functions that can we access at any location in our web apps.

In this article, we look at the `window.cryoto` object.

window.crypto
=============

The `window.crypto` property returns a `Crypto` object which is associated with the global object. This object allows web pages to run various cryptographic operations on the browser side. It has one property, which is the `subtle` property.

The `Crypto.subtle` property returns a `SubtleCrypto` object which allows us to do subtle cryptography on the client-side. The `SubtleCrypto` object has 5 methods for scrambling and unscrambling data. The `sign` method is for creating digital signatures.

A `verify` method exists to verify the digital signatures created by the `sign` method.

The `encrypt` method is used for encrypting data, and the `decrypt` method is used for decryption the scrambled data generated by the `encrypt` method. The `digest` method is used to create a fixed-length, collision-resistant digest of some data.

We can also use the `SubtleCrypto` object to generate and derive cryptographic keys with the `generateKey` and `deriveKey` methods respectively.

The `generateKey` method generates a new distinct key value each time we call it, while the `deriveKey` method derives a key from some initial material. If we provide the same material to 2 separate calls to `deriveKey` , we will get the same underlying value.

The `deriveKey` method is useful for deriving the same key for encryption and decryption. We can also use the `importKey` and `exportKey` methods to import and export cryptographic keys respectively.

There’s also a `wrapKey` method that exports the key and then encrypts it with another key.

An `unwrapKey` method is also provided to decrypt the encrypted key done by the `wrapKey` method and import the decrypted key.

For example, we can use the `sign` method to create a digital signature. It takes 3 arguments. The first is the `algorithm`, which is a string or an object that specifies the signature algorithm to use for creating the digital signature. Possible values are:

*   RSASSA-PKCS1-v1_5 — pass in the string `“RSASSA-PKCS1-v1_5”` or an object of the form `{ “name”: “RSASSA-PKCS1-v1_5” }`
*   RSA-PSS — pass an `RsaPssParams` object. An `RsaPssParams` object has the `name` property which should be `RSA-PSS` , and `saltLength` which is the length of the random salt to use measured in bytes. The maximum value of `saltLength` is `Math.ceil((keySizeInBits - 1)/8) - digestSizeInBytes - 2`
*   ECDSA — pass an `EcdsaParams` object. An `EcdsaParams` object has the `name` property, which should be the string `'ECDSA'` and the `hash` property, which is string that can have the possible values of `SHA-256`, `SHA-384` or `SHA-512`
*   HMAC — pass in the string `“HMAC”` or an object of the form `{ “name”: “HMAC” }`

The second argument is the `key` which is a CryptoKey object that has the private key to be used for creating the signature. The third argument is the `data` which is an `ArrayBuffer` or `ArrayBufferView` object that has the data to be signed.

The `sign` method returns a promise that’s fulfilled with an `ArrayBuffer` object that has the signature.

Likewise, the `verify` method takes in the same first `algorithm`, `key`, and `data` argument as the `sign` method as the first, second and fourth arguments. The `signature` generated from the `sign` method is the third argument. It returns a promise that fulfills with the value `true` if the signature is valid and `false` otherwise.

To use the `sign` and `verify` methods, we can write something like the following code:

```javascript
const enc = new TextEncoder();
const encodedMessage = enc.encode('hello');
const keyPair = window.crypto.subtle.generateKey({
    name: "RSASSA-PKCS1-v1_5",
    modulusLength: 4096,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
  },
  true,
  ["sign", "verify"]
);
(async () => {
  const {
    privateKey,
    publicKey
  } = await keyPair;
  const signature = await window.crypto.subtle.sign(
    "RSASSA-PKCS1-v1_5",
    privateKey,
    encodedMessage
  );
  const signatureValid = await window.crypto.subtle.verify("RSASSA-PKCS1-v1_5", publicKey, signature, encodedMessage);
  console.log(signatureValid);
})()
```

We first generate the key pair with the `generateKey` since we’re using the asymmetric RSA algorithm which has a private and public key. The `generateKey` method takes the algorithm as the first argument, where the possible values are:

*   To use [RSASSA-PKCS1-v1_5](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#RSASSA-PKCS1-v1_5), [RSA-PSS](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#RSA-PSS), or [RSA-OAEP](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#RSA-OAEP) we pass an [RsaHashedKeyGenParams](https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams) object.
*   To use [ECDSA](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#ECDSA) or [ECDH](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#ECDH) we pass an [EcKeyGenParams](https://developer.mozilla.org/en-US/docs/Web/API/EcKeyGenParams) object.
*   To use [HMAC](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#HMAC) we pass an [HmacKeyGenParams](https://developer.mozilla.org/en-US/docs/Web/API/HmacKeyGenParams) object.
*   To use [AES-CTR](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#AES-CTR), [AES-CBC](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#AES-CBC), [AES-GCM](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#AES-GCM), or [AES-KW](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#AES-KW) we pass an [AesKeyGenParams](https://developer.mozilla.org/en-US/docs/Web/API/AesKeyGenParams) object.

The second argument is the boolean `extractable` property which indicates whether it’s possible to export a key using the `SubtleCrypto.exportKey()` or `SubtleCrypto.wrapKey()` methods. The third argument is the `keyUsages` array which indicates which methods can be used with the keys generated:

*   `encrypt`
*   `decrypt`
*   `sign`
*   `verify`
*   `deriveKey`
*   `deriveBits`
*   `wrapKey`
*   `unwrapKey`

Then we call the `sign` method with the algorithm name, private key, and the encoded message we generated from the `TextEncoder` . This generates the signature. Then we call the `verify` method with the algorithm name, private key, the generated signature fulfilled from the `sign` method and the same encoded message. If we run the code above, we should get `console.log` logging `true` .


The `encrypt` method takes 3 arguments. The first is the `algorithm` , which is an object with the following possible values:

*   To use the RSA-OAEP algorithm, we pass in an `RsaOaepParams` object. Full details of the properties of the object are at [https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams](https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams)
*   To use AES-CTR algorithm, we pass in an `AesCtrParams` object. Full details of the properties of the object are at [https://developer.mozilla.org/en-US/docs/Web/API/AesCtrParams](https://developer.mozilla.org/en-US/docs/Web/API/AesCtrParams)
*   To use AES-CBC algorithm, we pass in an `AesCbcParams` object. Full details of the properties of the object are at [https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams](https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams)
*   To use AES-GCM algorithm, we pass in an `AesGcmParams` object. Full details of the properties of the object are at [https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams](https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams)

The second argument is the `CryptoKey` object which we use to do the encryption. The third argument is a `BufferSource` object that has the data to be encrypted, also known as plain text. It returns a promise that’s resolved with an `ArrayBuffer` object containing the encrypted plain text.

Likewise, the `decrypt` method takes the same first 2 arguments as the `encrypt` method, except that the third argument is a `BufferSource` that has the data to be decrypted. It returns a promise that’s resolved with the `ArrayBuffer` object which has the plain text.

For example, we can use the `encrypt` and `dercrypt` methods like in the following code:

```javascript
const enc = new TextEncoder();
const dec = new TextDecoder();
const keyPair = window.crypto.subtle.generateKey({
    name: "RSA-OAEP",
    modulusLength: 4096,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
  },
  true,
  ["encrypt", "decrypt"]
);
const encodedMessage = enc.encode('hello');
(async () => {
  const {
    privateKey,
    publicKey
  } = await keyPair;
  const encryptedText = await window.crypto.subtle.encrypt({
      name: "RSA-OAEP"
    },
    publicKey,
    encodedMessage
  )
  console.log(encryptedText);
  const decryptedText = await window.crypto.subtle.decrypt({
      name: "RSA-OAEP"
    },
    privateKey,
    encryptedText
  )
  console.log(decryptedText);
  console.log(dec.decode(decryptedText));
})()
```

In the code above, we first generate a key or key pair with the `generateKey` method with depending if the encryption algorithm is symmetric or asymmetric like we did with the `sign` and `verify` example. Asymmetric cryptographic algorithms have a public and private key like in the example above. RSA is an asymmetric algorithm.

Then we encode the message with the `TextEncoder` to encode it to a `ArrayBuffer` object which can used with the `encrypt` method.

Then we use the `encrypt` method with the algorithm, the public key, and the `ArrayBuffer` object with the encoded text passed int to encrypt the data. Then to decrypt the encrypted text, we use the `decrypt` method with the algorithm object passed in as the first argument, then we pass in the private key from the key pair, then we pass in the encrypted text as the third argument to the `decrypt` method.

This will get the decrypted data as an `ArrayBuffer` , which we will decode with the `TextDecoder`’s `decode` method with the decrypted `ArrayBuffer` to get back the original text. This means that the last `console.log` statement to get us back `'hello'`.

The `Crypto` object also has one method, which is the `getRandomValues` method. The method will create a strong random value given a typed array. The method takes one argument. It takes a typed array, which is an `Int8Array`, a `Uint8Array`, an `Int16Array`, a `Uint16Array`, an `Int32Array`, or a `Uint32Array`. To improve performance, this method doesn’t generate numbers with a truly random number generator, but rather it uses a pseudo-random number generator to generate the number. The entries of the typed array passed into the argument will be overwritten by the random numbers generated by this method.

We can use the `getRandomValues` method like in the following example:

```javascript
let array = new Uint32Array(10);
window.crypto.getRandomValues(array);
for (const num of array) {
  console.log(num);
}
```

In the code above, we generated a new `Uint32Array`, which we pass into the `getRandomValues` method. Then in the `for...of` loop, we get the generated values which overwrote whatever entries were in the original array. We should see 10 random numbers from the `console.log`, and each time we run the code above, we should get different results.

With the `window.cryoto` object, we can encrypt and decrypt data by using well-know cryptographic algorithms on the browser. It supports both symmetric and asymmetric encryption, which let us encrypt data with different algorithms. Also, we can use it to generate digital signatures and verify them. We can also use it to get random numbers with the `getRandomValues` method.