File

src/crypto/browser/crypto.ts

Implements

Crypto

Index

Methods

Constructor

constructor()

Methods

decodeBase64StringUtf8
decodeBase64StringUtf8(base64: string)
Parameters :
Name Type Optional
base64 string No
Returns : string
encodeBase64StringUtf8
encodeBase64StringUtf8(text: string)
Parameters :
Name Type Optional
text string No
Returns : string
randomBytesBase64
randomBytesBase64(count: number)
Parameters :
Name Type Optional
count number No
Returns : string
Async sha256DigestBase64
sha256DigestBase64(str: string)
Parameters :
Name Type Optional
str string No
Returns : Promise<string>
Async sign
sign(privateKey: JwkCertificate, data: string)
Parameters :
Name Type Optional
privateKey JwkCertificate No
data string No
Returns : Promise<string>
Async verify
verify(pubkey: JwkCertificate, data: string, signature: string)
Parameters :
Name Type Optional
pubkey JwkCertificate No
data string No
signature string No
Returns : Promise<boolean>
import * as base64js from 'base64-js';

// Not all browsers support `TextEncoder`. The following `require` will
// provide a fast UTF8-only replacement for those browsers that don't support
// text encoding natively.
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof process === 'undefined' && typeof TextEncoder === 'undefined') {
  require('fast-text-encoding');
}

import {Crypto, JwkCertificate} from '../crypto';

export class BrowserCrypto implements Crypto {
  constructor() {
    if (
      typeof window === 'undefined' ||
      window.crypto === undefined ||
      window.crypto.subtle === undefined
    ) {
      throw new Error(
        "SubtleCrypto not found. Make sure it's an https:// website."
      );
    }
  }

  async sha256DigestBase64(str: string): Promise<string> {
    // SubtleCrypto digest() method is async, so we must make
    // this method async as well.

    // To calculate SHA256 digest using SubtleCrypto, we first
    // need to convert an input string to an ArrayBuffer:
    // eslint-disable-next-line node/no-unsupported-features/node-builtins
    const inputBuffer = new TextEncoder().encode(str);

    // Result is ArrayBuffer as well.
    const outputBuffer = await window.crypto.subtle.digest(
      'SHA-256',
      inputBuffer
    );

    return base64js.fromByteArray(new Uint8Array(outputBuffer));
  }

  randomBytesBase64(count: number): string {
    const array = new Uint8Array(count);
    window.crypto.getRandomValues(array);
    return base64js.fromByteArray(array);
  }

  private static padBase64(base64: string): string {
    // base64js requires padding, so let's add some '='
    while (base64.length % 4 !== 0) {
      base64 += '=';
    }
    return base64;
  }

  async verify(
    pubkey: JwkCertificate,
    data: string,
    signature: string
  ): Promise<boolean> {
    const algo = {
      name: 'RSASSA-PKCS1-v1_5',
      hash: {name: 'SHA-256'},
    };
    // eslint-disable-next-line node/no-unsupported-features/node-builtins
    const dataArray = new TextEncoder().encode(data);
    const signatureArray = base64js.toByteArray(
      BrowserCrypto.padBase64(signature)
    );
    const cryptoKey = await window.crypto.subtle.importKey(
      'jwk',
      pubkey,
      algo,
      true,
      ['verify']
    );

    // SubtleCrypto's verify method is async so we must make
    // this method async as well.
    const result = await window.crypto.subtle.verify(
      algo,
      cryptoKey,
      signatureArray,
      dataArray
    );
    return result;
  }

  async sign(privateKey: JwkCertificate, data: string): Promise<string> {
    const algo = {
      name: 'RSASSA-PKCS1-v1_5',
      hash: {name: 'SHA-256'},
    };
    // eslint-disable-next-line node/no-unsupported-features/node-builtins
    const dataArray = new TextEncoder().encode(data);
    const cryptoKey = await window.crypto.subtle.importKey(
      'jwk',
      privateKey,
      algo,
      true,
      ['sign']
    );

    // SubtleCrypto's sign method is async so we must make
    // this method async as well.
    const result = await window.crypto.subtle.sign(algo, cryptoKey, dataArray);
    return base64js.fromByteArray(new Uint8Array(result));
  }

  decodeBase64StringUtf8(base64: string): string {
    const uint8array = base64js.toByteArray(BrowserCrypto.padBase64(base64));
    // eslint-disable-next-line node/no-unsupported-features/node-builtins
    const result = new TextDecoder().decode(uint8array);
    return result;
  }

  encodeBase64StringUtf8(text: string): string {
    // eslint-disable-next-line node/no-unsupported-features/node-builtins
    const uint8array = new TextEncoder().encode(text);
    const result = base64js.fromByteArray(uint8array);
    return result;
  }
}

result-matching ""

    No results matching ""