"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const MD5 = require('js-md5');
const crypto_web_1 = require("./crypto.web");
function addPadding(b, k) {
    const padLen = k - (b.length % k);
    const paddingBytes = new Uint8Array(padLen);
    paddingBytes.fill(padLen);
    return mergeUint8Array(b, paddingBytes);
}
const saltPrefix = crypto_web_1.fromString('Salted__');
function encrypt(input, secret) {
    return __awaiter(this, void 0, void 0, function* () {
        const salt = crypto_web_1.randomBytes(8);
        const pbe = yield generateKey(secret, salt);
        const saltBlock = mergeUint8Array(saltPrefix, salt);
        const enc = new TextEncoder();
        const result = yield crypto.subtle.encrypt({
            name: 'AES-CBC',
            iv: pbe.iv,
        }, pbe.key, enc.encode(input));
        return mergeUint8Array(saltBlock, new Uint8Array(result));
    });
}
exports.encrypt = encrypt;
function decrypt(cipherText, secret) {
    return __awaiter(this, void 0, void 0, function* () {
        const salt = cipherText.slice(8, 16);
        const data = cipherText.slice(16);
        const pbe = yield generateKey(secret, salt);
        const result = yield crypto.subtle.decrypt({
            name: 'AES-CBC',
            iv: pbe.iv,
        }, pbe.key, data);
        return new Uint8Array(result);
    });
}
exports.decrypt = decrypt;
function md5(buffer) {
    const hash = MD5.array(buffer);
    return new Uint8Array(hash);
}
function mergeUint8Array(array1, array2) {
    const mergedArray = new Uint8Array(array1.length + array2.length);
    mergedArray.set(array1);
    mergedArray.set(array2, array1.length);
    return mergedArray;
}
exports.mergeUint8Array = mergeUint8Array;
function generateKey(secret, salt) {
    return __awaiter(this, void 0, void 0, function* () {
        const md5Hash = [];
        const data00 = mergeUint8Array(new Uint8Array(secret), salt);
        md5Hash[0] = md5(data00);
        let result = md5Hash[0];
        for (let i = 1; i < 3; i += 1) {
            md5Hash[i] = md5(mergeUint8Array(md5Hash[i - 1], data00));
            result = mergeUint8Array(result, md5Hash[i]);
        }
        return {
            key: yield crypto_web_1.importSecretKey(result.slice(0, 32)),
            iv: result.slice(32, 48),
        };
    });
}
