import { workerHandler } from 'src/app/shared/worker-handler/worker-handler';
import { WorkerOperation } from 'src/app/shared/worker-handler/worker-common';

/**
 * Primary SIV cipher config with a medium sized nonce for extra security.
 */
export class AESCipherSIVNonce96 /*extends AESCipherSIVNonce96Worker*/ {
  public static encrypt(
    plain: Uint8Array,
    key: Uint8Array,
    nonce?: Uint8Array,
    assoc: Uint8Array = new Uint8Array([]),
    prefix: Uint8Array = new Uint8Array([])
  ): Promise<Uint8Array> {
    return workerHandler.run(
      WorkerOperation.AESCipherSIVNonce96Encrypt,
      plain,
      key,
      nonce,
      assoc,
      prefix
    );
  }

  public static decrypt(
    cipher: Uint8Array,
    key: Uint8Array,
    assoc: Uint8Array = new Uint8Array([])
  ): Promise<Uint8Array> {
    return workerHandler.run(WorkerOperation.AESCipherSIVNonce96Decrypt, cipher, key, assoc);
  }

  public static describe(): string {
    return 'AES-SIV-N96-128/256';
  }
}

/**
 * Deterministic SIV encryption by not using a nonce.
    RFC5297 Section 4:
    In case AES SIV is used for key wrapping it is not necessary to provide a nonce component.
 */
export class AESCipherSIVDeterministic /*extends AESCipherSIVDeterministicWorker*/ {
  public static encrypt(
    plain: Uint8Array,
    key: Uint8Array,
    assoc?: Uint8Array,
    prefix: Uint8Array = new Uint8Array([])
  ): Promise<Uint8Array> {
    return workerHandler.run(
      WorkerOperation.AESCipherSIVDeterministicEncrypt,
      plain,
      key,
      assoc,
      prefix
    );
  }

  public static decrypt(
    cipher: Uint8Array,
    key: Uint8Array,
    assoc?: Uint8Array
  ): Promise<Uint8Array> {
    return workerHandler.run(WorkerOperation.AESCipherSIVDeterministicDecrypt, cipher, key, assoc);
  }

  public static describe(): string {
    return 'AES-SIV-N0-128/256';
  }
}

/**
 * One of the most widely used and generally good AES constructs.
    The security is prone to breaking by repeating nonce values if not coordinated by the participants.
 */
export class AESCipherGCM /*extends AESCipherGCMWorker*/ {
  public static encrypt(
    plain: Uint8Array,
    key: Uint8Array,
    nonce?: Uint8Array,
    assoc?: Uint8Array,
    prefix?: Uint8Array
  ): Promise<Uint8Array> {
    return workerHandler.run(WorkerOperation.AESCipherGCMEncrypt, plain, key, nonce, assoc, prefix);
  }

  public static decrypt(
    cipher: Uint8Array,
    key: Uint8Array,
    assoc?: Uint8Array
  ): Promise<Uint8Array> {
    return workerHandler.run(WorkerOperation.AESCipherGCMDecrypt, cipher, key, assoc);
  }

  public static describe(): string {
    return 'AES-GCM-128/256';
  }
}

/**
 * The simplest yet sometimes adequate and usable AES mode.
    NOTE: DO NOT USE THIS, PADDING PROBLEMS +-16 btes at the end of the encrypted data
*/
export class AESCipherCBC /*extends AESCipherCBCWorker*/ {
  public static encrypt(
    plain: Uint8Array,
    key: Uint8Array,
    iv?: Uint8Array,
    prefix: Uint8Array = new Uint8Array([])
  ): Promise<Uint8Array> {
    return workerHandler.run(WorkerOperation.AESCipherCBCEncrypt, plain, key, iv, prefix);
  }

  public static decrypt(cipher: Uint8Array, key: Uint8Array): Promise<Uint8Array> {
    return workerHandler.run(WorkerOperation.AESCipherCBCDecrypt, cipher, key);
  }

  public static describe(): string {
    return 'AES-CBC-128/256';
  }
}
