"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EncryptionUtil = exports.INITIALIZATION_VECTOR_LENGTH = exports.DecryptError = void 0;
const crypto_1 = __importDefault(require("crypto"));
const protocol_1 = require("@streamr/protocol");
class DecryptError extends protocol_1.StreamMessageError {
    constructor(streamMessage, message = '') {
        super(`Decrypt error: ${message}`, streamMessage);
    }
}
exports.DecryptError = DecryptError;
exports.INITIALIZATION_VECTOR_LENGTH = 16;
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
class EncryptionUtil {
    static validateRSAPublicKey(publicKey) {
        const keyString = typeof publicKey === 'string' ? publicKey : publicKey.toString('utf8');
        if (typeof keyString !== 'string' || !keyString.startsWith('-----BEGIN PUBLIC KEY-----')
            || !keyString.endsWith('-----END PUBLIC KEY-----\n')) {
            throw new Error('"publicKey" must be a PKCS#8 RSA public key in the PEM format');
        }
    }
    static encryptWithRSAPublicKey(plaintextBuffer, publicKey) {
        this.validateRSAPublicKey(publicKey);
        const ciphertextBuffer = crypto_1.default.publicEncrypt(publicKey, plaintextBuffer);
        return ciphertextBuffer;
    }
    static decryptWithRSAPrivateKey(ciphertext, privateKey) {
        return crypto_1.default.privateDecrypt(privateKey, ciphertext);
    }
    /*
     * Returns a hex string without the '0x' prefix.
     */
    static encryptWithAES(data, cipherKey) {
        const iv = crypto_1.default.randomBytes(exports.INITIALIZATION_VECTOR_LENGTH); // always need a fresh IV when using CTR mode
        const cipher = crypto_1.default.createCipheriv('aes-256-ctr', cipherKey, iv);
        return Buffer.concat([iv, cipher.update(data), cipher.final()]);
    }
    /*
     * 'ciphertext' must be a hex string (without '0x' prefix), 'groupKey' must be a GroupKey. Returns a Buffer.
     */
    static decryptWithAES(cipher, cipherKey) {
        const iv = cipher.slice(0, exports.INITIALIZATION_VECTOR_LENGTH);
        const decipher = crypto_1.default.createDecipheriv('aes-256-ctr', cipherKey, iv);
        return Buffer.concat([decipher.update(cipher.slice(exports.INITIALIZATION_VECTOR_LENGTH)), decipher.final()]);
    }
    static decryptStreamMessage(streamMessage, groupKey) {
        let content;
        try {
            content = this.decryptWithAES(streamMessage.content, groupKey.data);
        }
        catch (err) {
            throw new DecryptError(streamMessage, err.stack);
        }
        let newGroupKey = undefined;
        if (streamMessage.newGroupKey) {
            try {
                newGroupKey = groupKey.decryptNextGroupKey(streamMessage.newGroupKey);
            }
            catch (err) {
                throw new DecryptError(streamMessage, `Could not decrypt new group key: ${err.stack}`);
            }
        }
        return [content, newGroupKey];
    }
}
exports.EncryptionUtil = EncryptionUtil;
//# sourceMappingURL=EncryptionUtil.js.map