"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
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 });
exports.EncryptionAlgorithm = exports.Encryption = void 0;
const crypto = __importStar(require("crypto"));
const eciesjs = __importStar(require("eciesjs"));
const readable_stream_1 = require("readable-stream");
// import { webcrypto } from 'node:crypto';
// // @ts-ignore
// if (!globalThis.crypto) {globalThis.crypto = webcrypto;}
/**
 * Utility class for performing common, non-DWN specific encryption operations.
 */
class Encryption {
    /**
     * Encrypts the given plaintext stream using AES-256-CTR algorithm.
     */
    static aes256CtrEncrypt(key, initializationVector, plaintextStream) {
        return __awaiter(this, void 0, void 0, function* () {
            const cipher = crypto.createCipheriv('aes-256-ctr', key, initializationVector);
            const cipherStream = new readable_stream_1.Readable({
                read() { }
            });
            plaintextStream.on('data', (chunk) => {
                const encryptedChunk = cipher.update(chunk);
                cipherStream.push(encryptedChunk);
            });
            plaintextStream.on('end', () => {
                const finalChunk = cipher.final();
                cipherStream.push(finalChunk);
                cipherStream.push(null);
            });
            plaintextStream.on('error', (err) => {
                cipherStream.emit('error', err);
            });
            return cipherStream;
        });
    }
    /**
     * Decrypts the given cipher stream using AES-256-CTR algorithm.
     */
    static aes256CtrDecrypt(key, initializationVector, cipherStream) {
        return __awaiter(this, void 0, void 0, function* () {
            const decipher = crypto.createDecipheriv('aes-256-ctr', key, initializationVector);
            const plaintextStream = new readable_stream_1.Readable({
                read() { }
            });
            cipherStream.on('data', (chunk) => {
                const decryptedChunk = decipher.update(chunk);
                plaintextStream.push(decryptedChunk);
            });
            cipherStream.on('end', () => {
                const finalChunk = decipher.final();
                plaintextStream.push(finalChunk);
                plaintextStream.push(null);
            });
            cipherStream.on('error', (err) => {
                plaintextStream.emit('error', err);
            });
            return plaintextStream;
        });
    }
    /**
     * Encrypts the given plaintext using ECIES (Elliptic Curve Integrated Encryption Scheme)
     * with SECP256K1 for the asymmetric calculations, HKDF as the key-derivation function,
     * and AES-GCM for the symmetric encryption and MAC algorithms.
     */
    static eciesSecp256k1Encrypt(uncompressedPublicKey, plaintext) {
        return __awaiter(this, void 0, void 0, function* () {
            // underlying library requires Buffer as input
            const publicKey = Buffer.from(uncompressedPublicKey);
            const plaintextBuffer = Buffer.from(plaintext);
            const cryptogram = eciesjs.encrypt(publicKey, plaintextBuffer);
            // split cryptogram returned into constituent parts
            const ephemeralPublicKey = cryptogram.subarray(0, 65);
            const initializationVector = cryptogram.subarray(65, 81);
            const messageAuthenticationCode = cryptogram.subarray(81, 97);
            const ciphertext = cryptogram.subarray(97);
            return {
                ciphertext,
                ephemeralPublicKey,
                initializationVector,
                messageAuthenticationCode
            };
        });
    }
    /**
     * Decrypt the given plaintext using ECIES (Elliptic Curve Integrated Encryption Scheme)
     * with SECP256K1 for the asymmetric calculations, HKDF as the key-derivation function,
     * and AES-GCM for the symmetric encryption and MAC algorithms.
     */
    static eciesSecp256k1Decrypt(input) {
        return __awaiter(this, void 0, void 0, function* () {
            // underlying library requires Buffer as input
            const privateKeyBuffer = Buffer.from(input.privateKey);
            const eciesEncryptionOutput = Buffer.concat([
                input.ephemeralPublicKey,
                input.initializationVector,
                input.messageAuthenticationCode,
                input.ciphertext
            ]);
            const plaintext = eciesjs.decrypt(privateKeyBuffer, eciesEncryptionOutput);
            return plaintext;
        });
    }
}
exports.Encryption = Encryption;
var EncryptionAlgorithm;
(function (EncryptionAlgorithm) {
    EncryptionAlgorithm["Aes256Ctr"] = "A256CTR";
    EncryptionAlgorithm["EciesSecp256k1"] = "ECIES-ES256K";
})(EncryptionAlgorithm || (exports.EncryptionAlgorithm = EncryptionAlgorithm = {}));
//# sourceMappingURL=encryption.js.map