# All files / src/encryption aesCipher.ts

90.24% Statements 37/41
77.78% Branches 14/18
100% Functions 7/7
90.24% Lines 37/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    1291x

    1x

    41x
    41x

    23x

    23x
    23x
    23x

    21x

    21x
    21x
    19x

    1x

    1x

    2x
    1x
    1x
    1x
    1x
    1x

    2x

    2x
    2x

    2x
    1x
    1x
    1x
    1x
    1x

    2x

    2x
    2x

    1x
    42x
    42x
    1x

    41x

     import { getCryptoLib } from './cryptoUtils'

    type NodeCryptoCreateCipher = typeof import('crypto').createCipheriv;
    type NodeCryptoCreateDecipher = typeof import('crypto').createDecipheriv;

    export type CipherAlgorithm = 'aes-256-cbc' | 'aes-128-cbc';

    export interface AesCipher {
      encrypt(
        algorithm: CipherAlgorithm,
        key: Buffer,
        iv: Buffer,
        data: Buffer): Promise<Buffer>;

      decrypt(
        algorithm: CipherAlgorithm,
        key: Buffer,
        iv: Buffer,
        data: Buffer): Promise<Buffer>;
    }

    export class NodeCryptoAesCipher implements AesCipher {
      createCipher: NodeCryptoCreateCipher

      createDecipher: NodeCryptoCreateDecipher

      constructor(createCipher: NodeCryptoCreateCipher, createDecipher: NodeCryptoCreateDecipher) {
        this.createCipher = createCipher
        this.createDecipher = createDecipher
      }

      async encrypt(
        algorithm: CipherAlgorithm,
        key: Buffer,
        iv: Buffer,
        data: Buffer):
        Promise<Buffer> {
        Iif (algorithm !== 'aes-128-cbc' && algorithm !== 'aes-256-cbc') {
          throw new Error(`Unsupported cipher algorithm "${algorithm}"`)
        }
        const cipher = this.createCipher(algorithm, key, iv)
        const result = Buffer.concat([cipher.update(data), cipher.final()])
        return Promise.resolve(result)
      }

      async decrypt(
        algorithm: CipherAlgorithm,
        key: Buffer,
        iv: Buffer,
        data: Buffer):
        Promise<Buffer> {
        Iif (algorithm !== 'aes-128-cbc' && algorithm !== 'aes-256-cbc') {
          throw new Error(`Unsupported cipher algorithm "${algorithm}"`)
        }
        const cipher = this.createDecipher(algorithm, key, iv)
        const result = Buffer.concat([cipher.update(data), cipher.final()])
        return Promise.resolve(result)
      }
    }

    export class WebCryptoAesCipher implements AesCipher {
      subtleCrypto: SubtleCrypto

      constructor(subtleCrypto: SubtleCrypto) {
        this.subtleCrypto = subtleCrypto
      }

      async encrypt(
        algorithm: CipherAlgorithm,
        key: Buffer,
        iv: Buffer,
        data: Buffer):
        Promise<Buffer> {
        let algo: string
        let length: number
        if (algorithm === 'aes-128-cbc') {
          algo = 'AES-CBC'
          length = 128
        } else Eif (algorithm === 'aes-256-cbc') {
          algo = 'AES-CBC'
          length = 256
        } else {
          throw new Error(`Unsupported cipher algorithm "${algorithm}"`)
        }
        const cryptoKey = await this.subtleCrypto.importKey(
          'raw', key,
          { name: algo, length },
          false, ['encrypt']
        )
        const result = await this.subtleCrypto.encrypt({ name: algo, iv }, cryptoKey, data)
        return Buffer.from(result)
      }

      async decrypt(
        algorithm: CipherAlgorithm,
        key: Buffer,
        iv: Buffer,
        data: Buffer):
        Promise<Buffer> {
        let algo: string
        let length: number
        if (algorithm === 'aes-128-cbc') {
          algo = 'AES-CBC'
          length = 128
        } else Eif (algorithm === 'aes-256-cbc') {
          algo = 'AES-CBC'
          length = 256
        } else {
          throw new Error(`Unsupported cipher algorithm "${algorithm}"`)
        }
        const cryptoKey = await this.subtleCrypto.importKey(
          'raw', key,
          { name: algo, length },
          false, ['decrypt']
        )
        const result = await this.subtleCrypto.decrypt({ name: algo, iv }, cryptoKey, data)
        return Buffer.from(result)
      }
    }

    export async function createCipher(): Promise<AesCipher> {
      const cryptoLib = await getCryptoLib()
      if (cryptoLib.name === 'subtleCrypto') {
        return new WebCryptoAesCipher(cryptoLib.lib)
      } else {
        return new NodeCryptoAesCipher(cryptoLib.lib.createCipheriv, cryptoLib.lib.createDecipheriv)
      }
    }