UNPKG

cross-crypto-ts

Version:

Cifrado híbrido AES-GCM + RSA-OAEP con interoperabilidad entre TypeScript y Python, con diseño compatible para Rust.

122 lines (121 loc) 4.74 kB
"use strict"; // src/file_crypto.ts var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.encryptFileHybrid = encryptFileHybrid; exports.decryptFileHybrid = decryptFileHybrid; const fs_1 = __importDefault(require("fs")); const encrypt_1 = require("./encrypt"); const core_1 = require("./core"); const decrypt_1 = require("./decrypt"); const STREAM_ENVELOPE_MAGIC = Buffer.from("CCRYPT2\n", "utf8"); function isStreamEnvelopeFile(filePath) { try { if (!fs_1.default.existsSync(filePath) || !fs_1.default.statSync(filePath).isFile()) { return false; } const fd = fs_1.default.openSync(filePath, "r"); const magic = Buffer.alloc(STREAM_ENVELOPE_MAGIC.length); try { const n = fs_1.default.readSync(fd, magic, 0, magic.length, 0); return n === magic.length && magic.equals(STREAM_ENVELOPE_MAGIC); } finally { fs_1.default.closeSync(fd); } } catch { return false; } } function outputBase(encPath) { if (encPath.endsWith(".enc.json")) return encPath.slice(0, -9); if (encPath.endsWith(".ccenc")) return encPath.slice(0, -6); if (encPath.endsWith(".enc")) return encPath.slice(0, -4); return encPath; } function encryptFileHybrid(paths, publicKey, options = {}) { if (!paths.length || !paths.every(fs_1.default.existsSync)) { throw new Error("Una o más rutas no existen o la lista está vacía."); } const zipName = options.zipOutput || `temp_${Date.now()}.zip`; const zipPath = (0, core_1.createZipFromPaths)(paths, zipName); try { const useStream = options.useStream ?? false; if (useStream) { const outPath = options.outputEnc || zipPath + ".ccenc"; const encrypted = (0, encrypt_1.encryptHybrid)(zipPath, publicKey, "stream", { oaepHash: options.oaepHash, aad: options.aad, outputPath: outPath, contentMode: "binary", streamChunkSize: options.streamChunkSize, }); encrypted.originalPaths = paths; encrypted.originalPathsRel = paths.map((p) => p.split(/[\\/]/).pop() ?? p); if (options.attachMetadata) { encrypted.meta = (0, core_1.collectMetadata)(zipPath); } return encrypted; } const binaryData = (0, core_1.readBinaryFile)(zipPath); const encrypted = (0, encrypt_1.encryptHybrid)(binaryData, publicKey, "binary", { oaepHash: options.oaepHash, aad: options.aad, }); encrypted.originalPaths = paths; encrypted.originalPathsRel = paths.map((p) => p.split(/[\\/]/).pop() ?? p); if (options.attachMetadata) { encrypted.meta = (0, core_1.collectMetadata)(zipPath); } if (options.saveFile) { const outPath = options.outputEnc || zipPath + ".enc.json"; (0, core_1.saveEncryptedJson)(outPath, encrypted); } return encrypted; } finally { if (fs_1.default.existsSync(zipPath)) { fs_1.default.unlinkSync(zipPath); } } } function decryptFileHybrid(encPath, privateKey, extractTo, cleanupZip = true, options = {}) { if (!fs_1.default.existsSync(encPath)) { throw new Error(`Archivo cifrado no encontrado: ${encPath}`); } const base = outputBase(encPath); const tempZipPath = base + ".zip"; try { if (isStreamEnvelopeFile(encPath)) { const decryptedPath = (0, decrypt_1.decryptHybrid)(encPath, privateKey, tempZipPath, { oaepHash: options.oaepHash, aad: options.aad, }); if (typeof decryptedPath !== "string") { throw new Error("El descifrado stream no devolvió una ruta de archivo."); } } else { const encryptedObj = (0, core_1.loadEncryptedJson)(encPath); const decryptedBinary = (0, decrypt_1.decryptHybrid)(encryptedObj, privateKey, { oaepHash: options.oaepHash, aad: options.aad, }); (0, core_1.writeBinaryFile)(tempZipPath, Buffer.from(decryptedBinary)); } const outputDir = extractTo || base + "_output"; (0, core_1.extractZipToDir)(tempZipPath, outputDir); return outputDir; } finally { if (cleanupZip && fs_1.default.existsSync(tempZipPath)) { fs_1.default.unlinkSync(tempZipPath); } } }