UNPKG

pooja-docucomb-tink-crypto

Version:

A multi-language, cross-platform library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse.

87 lines (78 loc) 2.66 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {SecurityException} from '../exception/security_exception'; import * as Bytes from './bytes'; import {IndCpaCipher} from './ind_cpa_cipher'; import * as Random from './random'; import * as Validators from './validators'; /** * The minimum IV size. * */ const MIN_IV_SIZE_IN_BYTES: number = 12; /** * AES block size. * */ const AES_BLOCK_SIZE_IN_BYTES: number = 16; /** * Implementation of AES-CTR. * * @final */ export class AesCtr implements IndCpaCipher { /** * @param ivSize the size of the IV */ constructor( private readonly key: CryptoKey, private readonly ivSize: number) {} /** */ async encrypt(plaintext: Uint8Array): Promise<Uint8Array> { Validators.requireUint8Array(plaintext); const iv = Random.randBytes(this.ivSize); const counter = new Uint8Array(AES_BLOCK_SIZE_IN_BYTES); counter.set(iv); const alg = {'name': 'AES-CTR', 'counter': counter, 'length': 128}; const ciphertext = await self.crypto.subtle.encrypt(alg, this.key, plaintext); return Bytes.concat(iv, new Uint8Array(ciphertext)); } /** */ async decrypt(ciphertext: Uint8Array): Promise<Uint8Array> { Validators.requireUint8Array(ciphertext); if (ciphertext.length < this.ivSize) { throw new SecurityException('ciphertext too short'); } const counter = new Uint8Array(AES_BLOCK_SIZE_IN_BYTES); counter.set(ciphertext.subarray(0, this.ivSize)); const alg = {'name': 'AES-CTR', 'counter': counter, 'length': 128}; return new Uint8Array(await self.crypto.subtle.decrypt( alg, this.key, new Uint8Array(ciphertext.subarray(this.ivSize)))); } } /** * @param ivSize the size of the IV, must be larger than or equal to * {@link MIN_IV_SIZE_IN_BYTES} */ export async function fromRawKey( key: Uint8Array, ivSize: number): Promise<IndCpaCipher> { if (!Number.isInteger(ivSize)) { throw new SecurityException('invalid IV length, must be an integer'); } if (ivSize < MIN_IV_SIZE_IN_BYTES || ivSize > AES_BLOCK_SIZE_IN_BYTES) { throw new SecurityException( 'invalid IV length, must be at least ' + MIN_IV_SIZE_IN_BYTES + ' and at most ' + AES_BLOCK_SIZE_IN_BYTES); } Validators.requireUint8Array(key); Validators.validateAesKeySize(key.length); const cryptoKey = await self.crypto.subtle.importKey( 'raw', key, {'name': 'AES-CTR', 'length': key.length}, false, ['encrypt', 'decrypt']); return new AesCtr(cryptoKey, ivSize); }