Skip to content
Snippets Groups Projects
CryptoServiceWeb.ts 5.13 KiB
Newer Older
  • Learn to ignore specific revisions
  • import md5 from "js-md5";
    
    import { AESGCMOutput, ICryptoService, RSAKeys } from "./ICryptoService";
    
    import { base64ToArrayBuffer } from "../../utils/common";
    
    const exportKey = async (key: CryptoKey): Promise<ArrayBuffer> => {
    
      return crypto.subtle.exportKey("raw", key);
    
    const convertPemToBinary = (pem: string) => {
      const lines = pem.split("\n");
      let encoded = "";
      for (let i = 0; i < lines.length; i++) {
        if (
          lines[i].trim().length > 0 &&
          lines[i].indexOf("-BEGIN PRIVATE KEY-") < 0 &&
          lines[i].indexOf("-BEGIN PUBLIC KEY-") < 0 &&
          lines[i].indexOf("-END PRIVATE KEY-") < 0 &&
          lines[i].indexOf("-END PUBLIC KEY-") < 0
        ) {
          encoded += lines[i].trim();
        }
      }
      return base64ToArrayBuffer(encoded);
    };
    
    
    const getBytes = (value: string | ArrayBuffer, encoding): ArrayBuffer => {
    
      let bytes;
      if (typeof value === "string") {
        if (encoding === "base64") {
          bytes = base64ToArrayBuffer(value);
        } else {
          const encoder = new TextEncoder();
          bytes = encoder.encode(value);
        }
      } else {
        bytes = value;
      }
    
    class CryptoServiceWeb implements ICryptoService {
      public async encryptAESGCM(data: string): Promise<AESGCMOutput>;
      public async encryptAESGCM(data: ArrayBuffer): Promise<AESGCMOutput>;
      public async encryptAESGCM(
        data: string | ArrayBuffer
      ): Promise<AESGCMOutput> {
        const key = await crypto.subtle.generateKey(
          {
            name: "AES-GCM",
            length: 256,
          },
          true,
          ["encrypt", "decrypt"]
        );
    
        let encoded;
        if (typeof data === "string") {
          encoded = new TextEncoder().encode(data);
        } else {
          encoded = data;
        }
        const iv = crypto.getRandomValues(new Buffer(12));
        const encrypted = await crypto.subtle.encrypt(
          { name: "AES-GCM", iv: iv },
          key,
          encoded
        );
        return { data: encrypted, key: await exportKey(key), iv };
      }
    
      public async decryptAESGCM(
        data: ArrayBuffer,
        key: ArrayBuffer,
        iv: ArrayBuffer
      ): Promise<string>;
      public async decryptAESGCM(
        data: ArrayBuffer,
        key: ArrayBuffer,
        iv: ArrayBuffer,
        returnBuffer: true
      ): Promise<ArrayBuffer>;
      public async decryptAESGCM(
        data: ArrayBuffer,
        key: ArrayBuffer,
        iv: ArrayBuffer,
        returnBuffer?: boolean
      ): Promise<string | ArrayBuffer> {
        const importedKey = await crypto.subtle.importKey(
          "raw",
          key,
          {
            name: "AES-GCM",
            length: 256,
          },
          true,
          ["encrypt", "decrypt"]
        );
    
        const decrypted = await crypto.subtle.decrypt(
          { name: "AES-GCM", iv: iv },
          importedKey,
          data
        );
    
        return new TextDecoder().decode(decrypted);
      }
    
      public async verifyRSASignature(
        publicKeyPEM: string,
        data: ArrayBuffer,
        signature: ArrayBuffer
      ): Promise<boolean> {
        const publicKey = await crypto.subtle.importKey(
          "spki",
          convertPemToBinary(publicKeyPEM),
          {
            name: "RSASSA-PKCS1-v1_5",
            hash: "SHA-256",
          },
          true,
          ["verify"]
        );
    
        return await crypto.subtle.verify(
          {
            name: "RSASSA-PKCS1-v1_5",
            hash: "SHA-256",
          },
          publicKey,
          signature,
          data
        );
      }
    
      public async generateRSAKeys(): Promise<RSAKeys> {
        throw new Error("The function is not implemented");
      }
    
      public async encryptRSA(
        publicKeyPEM: string,
        data: ArrayBuffer
      ): Promise<ArrayBuffer> {
        const publicKey = await crypto.subtle.importKey(
          "spki",
          convertPemToBinary(publicKeyPEM),
          {
            name: "RSA-OAEP",
            hash: "SHA-256",
          },
          true,
          ["encrypt"]
        );
    
        return crypto.subtle.encrypt(
          {
            name: "RSA-OAEP",
          },
          publicKey,
          data
        );
      }
    
      public async decryptRSA(
        privateKeyPEM: string,
        data: ArrayBuffer
      ): Promise<ArrayBuffer> {
        throw new Error("The function is not implemented");
      }
    
      public async signRSA(
        privateKeyPEM: string,
        data: ArrayBuffer
      ): Promise<ArrayBuffer> {
        throw new Error("The function is not implemented");
      }
    
      public async SHA1(
        value: string | ArrayBuffer,
        encoding = "utf8"
      ): Promise<ArrayBuffer> {
        const bytes = getBytes(value, encoding);
        return await crypto.subtle.digest("SHA-1", bytes);
      }
    
      public async SHA256(
        value: string | ArrayBuffer,
        encoding = "utf8"
      ): Promise<ArrayBuffer> {
        const bytes = getBytes(value, encoding);
        return await crypto.subtle.digest("SHA-256", bytes);
      }
    
      public async SHA384(
        value: string | ArrayBuffer,
        encoding = "utf8"
      ): Promise<ArrayBuffer> {
        const bytes = getBytes(value, encoding);
        return await crypto.subtle.digest("SHA-384", bytes);
      }
    
      public async SHA512(
        value: string | ArrayBuffer,
        encoding = "utf8"
      ): Promise<ArrayBuffer> {
        const bytes = getBytes(value, encoding);
        return await crypto.subtle.digest("SHA-512", bytes);
      }
    
      public async MD5(
        value: string | ArrayBuffer,
        encoding = "utf8"
      ): Promise<ArrayBuffer> {
        const bytes = getBytes(value, encoding);
        return md5.arrayBuffer(bytes);
      }
    }