import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
/*
Copyright 2020 - 2021 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { decodeBase64, encodeBase64 } from "../base64.js";

// salt for HKDF, with 8 bytes of zeros
var zeroSalt = new Uint8Array(8);
/**
 * Encrypt a string using AES-CTR.
 *
 * @param data - the plaintext to encrypt
 * @param key - the encryption key to use as an input to the HKDF function which is used to derive the AES key for
 *    encryption. Obviously, the same key must be provided when decrypting.
 * @param name - the name of the secret. Used as an input to the HKDF operation which is used to derive the AES key,
 *    so again the same value must be provided when decrypting.
 * @param ivStr - the base64-encoded initialization vector to use. If not supplied, a random one will be generated.
 *
 * @returns The encrypted result, including the ciphertext itself, the initialization vector (as supplied in `ivStr`,
 *   or generated), and an HMAC on the ciphertext — all base64-encoded.
 */
export function encryptAES(_x, _x2, _x3, _x4) {
  return _encryptAES.apply(this, arguments);
}

/**
 * Decrypt an AES-encrypted string.
 *
 * @param data - the encrypted data, returned by {@link encryptAES}.
 * @param key - the encryption key to use as an input to the HKDF function which is used to derive the AES key. Must
 *    be the same as provided to {@link encryptAES}.
 * @param name - the name of the secret. Also used as an input to the HKDF operation which is used to derive the AES
 *    key, so again must be the same as provided to {@link encryptAES}.
 */
function _encryptAES() {
  _encryptAES = _asyncToGenerator(function* (data, key, name, ivStr) {
    var iv;
    if (ivStr) {
      iv = decodeBase64(ivStr);
    } else {
      iv = new Uint8Array(16);
      globalThis.crypto.getRandomValues(iv);

      // clear bit 63 of the IV to stop us hitting the 64-bit counter boundary
      // (which would mean we wouldn't be able to decrypt on Android). The loss
      // of a single bit of iv is a price we have to pay.
      iv[8] &= 0x7f;
    }
    var [aesKey, hmacKey] = yield deriveKeys(key, name);
    var encodedData = new TextEncoder().encode(data);
    var ciphertext = yield globalThis.crypto.subtle.encrypt({
      name: "AES-CTR",
      counter: iv,
      length: 64
    }, aesKey, encodedData);
    var hmac = yield globalThis.crypto.subtle.sign({
      name: "HMAC"
    }, hmacKey, ciphertext);
    return {
      iv: encodeBase64(iv),
      ciphertext: encodeBase64(ciphertext),
      mac: encodeBase64(hmac)
    };
  });
  return _encryptAES.apply(this, arguments);
}
export function decryptAES(_x5, _x6, _x7) {
  return _decryptAES.apply(this, arguments);
}
function _decryptAES() {
  _decryptAES = _asyncToGenerator(function* (data, key, name) {
    var [aesKey, hmacKey] = yield deriveKeys(key, name);
    var ciphertext = decodeBase64(data.ciphertext);
    if (!(yield globalThis.crypto.subtle.verify({
      name: "HMAC"
    }, hmacKey, decodeBase64(data.mac), ciphertext))) {
      throw new Error("Error decrypting secret ".concat(name, ": bad MAC"));
    }
    var plaintext = yield globalThis.crypto.subtle.decrypt({
      name: "AES-CTR",
      counter: decodeBase64(data.iv),
      length: 64
    }, aesKey, ciphertext);
    return new TextDecoder().decode(new Uint8Array(plaintext));
  });
  return _decryptAES.apply(this, arguments);
}
function deriveKeys(_x8, _x9) {
  return _deriveKeys.apply(this, arguments);
} // string of zeroes, for calculating the key check
function _deriveKeys() {
  _deriveKeys = _asyncToGenerator(function* (key, name) {
    var hkdfkey = yield globalThis.crypto.subtle.importKey("raw", key, {
      name: "HKDF"
    }, false, ["deriveBits"]);
    var keybits = yield globalThis.crypto.subtle.deriveBits({
      name: "HKDF",
      salt: zeroSalt,
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore: https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/879
      info: new TextEncoder().encode(name),
      hash: "SHA-256"
    }, hkdfkey, 512);
    var aesKey = keybits.slice(0, 32);
    var hmacKey = keybits.slice(32);
    var aesProm = globalThis.crypto.subtle.importKey("raw", aesKey, {
      name: "AES-CTR"
    }, false, ["encrypt", "decrypt"]);
    var hmacProm = globalThis.crypto.subtle.importKey("raw", hmacKey, {
      name: "HMAC",
      hash: {
        name: "SHA-256"
      }
    }, false, ["sign", "verify"]);
    return Promise.all([aesProm, hmacProm]);
  });
  return _deriveKeys.apply(this, arguments);
}
var ZERO_STR = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

/** Calculate the MAC for checking the key.
 *
 * @param key - the key to use
 * @param iv - The initialization vector as a base64-encoded string.
 *     If omitted, a random initialization vector will be created.
 * @returns An object that contains, `mac` and `iv` properties.
 */
export function calculateKeyCheck(key, iv) {
  return encryptAES(ZERO_STR, key, "", iv);
}
//# sourceMappingURL=aes.js.map