crypto-guardian-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.npmrc ADDED
@@ -0,0 +1,2 @@
1
+ @jherostudio:registry=https://npm.pkg.github.com
2
+ //npm.pkg.github.com/:_authToken=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
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Crypto Guardian CLI 🛡️
2
+
3
+ A lightweight, secure, and interactive Command Line Interface (CLI) tool designed for cryptographic operations. Built natively in TypeScript and Node.js, it leverages hardware-backed cryptography to generate high-entropy military-grade passwords and securely encrypt sensitive data using advanced encryption standards.
4
+
5
+ Developed under the engineering standards of **Jhero Studio**.
6
+
7
+ ---
8
+
9
+ ## ⚡ Features
10
+
11
+ * **Military-Grade Password Generation:** Generates cryptographically secure random passwords using hardware entropy (`node:crypto`).
12
+ * **Shannon Entropy Calculation:** Real-time mathematical evaluation of password strength ($E = L \cdot \log_2(R)$) to classify security levels up to `MILITAR` status (>80 bits).
13
+ * **Advanced Data Encryption (AES-256-GCM):** Industry-standard symmetric encryption to secure `.env` files, API keys, or raw text blocks.
14
+ * **Authenticated Decryption:** Utilizes Galois/Counter Mode (GCM) authentication tags to prevent data tampering or unauthorized modifications.
15
+ * **Interactive Cyberpunk UI:** A clean, zero-dependency interactive console menu driven by the native Node.js `readline` module.
16
+
17
+ ---
18
+
19
+ ## 📂 Project Architecture
20
+
21
+ ```text
22
+ crypto-guardian-cli/
23
+ ├── src/
24
+ │ ├── index.ts # Main interactive CLI menu loop
25
+ │ ├── entropy.ts # Password generation & Shannon entropy logic
26
+ │ ├── cipher.ts # AES-256-GCM encryption & decryption modules
27
+ │ └── ui.ts # Console aesthetics and color handling
28
+ ├── package.json # Dependencies & project scripts
29
+ ├── tsconfig.json # TypeScript compiler configuration
30
+ └── README.md # Project documentation
31
+
32
+ ---
33
+
34
+ 🛠️ TECHNICAL STACK & SECURITY IMPLEMENTATION
35
+
36
+ - Runtime & Language: Node.js v23+ & TypeScript.
37
+ - Development Engine: tsx for high-performance, real-time TypeScript execution.
38
+ - Cryptographic Core: Native node:crypto using secure pseudo-random number generators (CSPRNG) via hardware.
39
+ - Key Derivation: scryptSync with a unique dynamic salt per session to mitigate rainbow table attacks.
40
+ - Commit Verification: 100% of the codebase is cryptographically signed with trusted GPG keys (Verified status).
41
+
42
+ ---
43
+
44
+ 🚀 GETTING STARTED
45
+
46
+ Prerequisites
47
+ Ensure you have Node.js installed on your machine (v23 or higher recommended).
48
+
49
+ Installation
50
+ 1. Clone repository
51
+ ```bash
52
+ git clone https://github.com/Jherostudio/crypto-guardian-cli.git
53
+ cd crypto-guardian-cli
54
+ ```
55
+ 2. Install dependencies
56
+
57
+ ```bash
58
+ npm install
59
+ ```
60
+
61
+ 3. Run the application
62
+
63
+ ```bash
64
+ npx tsx src/index.ts
65
+ ```
66
+ ---
67
+
68
+ 🕹️ USAGE SHOWCASE
69
+
70
+ 1. Generating a Secure Key
71
+ Choose option 1, enter your desired length (e.g., 16), and the system will output your password along with its calculated mathematical resistance:
72
+
73
+ Plaintext
74
+ ✅ Generada: L9jMKP$<#PHmQ@{$
75
+ 📊 Entropía: 104.87 bits [MILITAR]
76
+
77
+ 2. Encrypting Sensitive Data
78
+
79
+ Choose option 2, paste your data (such as raw database credentials), and establish a master phrase. The output is a secure payload structure containing salt:iv:authTag:cipherText:
80
+
81
+ Plaintext
82
+ 47e188f79133dbe...61f2aa3f58f8800cd3932a1242
83
+
84
+ ---
85
+
86
+ 📄 LICENSE
87
+ This project is open-source and available under the MIT License.
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "crypto-guardian-cli",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "type": "module",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "description": "",
13
+ "devDependencies": {
14
+ "@types/node": "^25.8.0",
15
+ "tsx": "^4.22.1",
16
+ "typescript": "^6.0.3"
17
+ }
18
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 1. Encriptar texto plano usando una frase maestra
3
+ */
4
+ export declare function encrypt(text: string, secretPhrase: string): string;
5
+ /**
6
+ * 2. Desencriptar el bloque asegurando la integridad
7
+ */
8
+ export declare function decrypt(cipherText: string, secretPhrase: string): string;
9
+ //# sourceMappingURL=cipher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cipher.d.ts","sourceRoot":"","sources":["cipher.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAkBlE;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAqBxE"}
package/src/cipher.js ADDED
@@ -0,0 +1,42 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
2
+ // Configuración del algoritmo estándar de la industria (AES-256 en modo GCM)
3
+ const ALGORITHM = 'aes-256-gcm';
4
+ const IV_LENGTH = 12; // Vector de inicialización para GCM
5
+ const SALT_LENGTH = 16;
6
+ /**
7
+ * 1. Encriptar texto plano usando una frase maestra
8
+ */
9
+ export function encrypt(text, secretPhrase) {
10
+ // Generar un salt y un IV aleatorios por cada encriptación para máxima seguridad
11
+ const salt = randomBytes(SALT_LENGTH);
12
+ const iv = randomBytes(IV_LENGTH);
13
+ // Derivar una llave segura de 32 bytes (256 bits) a partir de la frase del usuario
14
+ const key = scryptSync(secretPhrase, salt, 32);
15
+ const cipher = createCipheriv(ALGORITHM, key, iv);
16
+ let encrypted = cipher.update(text, 'utf8', 'hex');
17
+ encrypted += cipher.final('hex');
18
+ // Obtener el tag de autenticación (GCM asegura que el contenido no sea manipulado)
19
+ const authTag = cipher.getAuthTag().toString('hex');
20
+ // Empaquetar todo en una sola cadena para fácil almacenamiento
21
+ return `${salt.toString('hex')}:${iv.toString('hex')}:${authTag}:${encrypted}`;
22
+ }
23
+ /**
24
+ * 2. Desencriptar el bloque asegurando la integridad
25
+ */
26
+ export function decrypt(cipherText, secretPhrase) {
27
+ const [saltHex, ivHex, authTagHex, encryptedHex] = cipherText.split(':');
28
+ if (!saltHex || !ivHex || !authTagHex || !encryptedHex) {
29
+ throw new Error('El formato del texto cifrado es inválido.');
30
+ }
31
+ const salt = Buffer.from(saltHex, 'hex');
32
+ const iv = Buffer.from(ivHex, 'hex');
33
+ const authTag = Buffer.from(authTagHex, 'hex');
34
+ // Derivar exactamente la misma llave usando la frase maestra y el salt original
35
+ const key = scryptSync(secretPhrase, salt, 32);
36
+ const decipher = createDecipheriv(ALGORITHM, key, iv);
37
+ decipher.setAuthTag(authTag);
38
+ let decrypted = decipher.update(encryptedHex, 'hex', 'utf8');
39
+ decrypted += decipher.final('utf8');
40
+ return decrypted;
41
+ }
42
+ //# sourceMappingURL=cipher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cipher.js","sourceRoot":"","sources":["cipher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAExF,6EAA6E;AAC7E,MAAM,SAAS,GAAG,aAAa,CAAC;AAChC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,oCAAoC;AAC1D,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,YAAoB;IACtD,iFAAiF;IACjF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAElC,mFAAmF;IACnF,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAE/C,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAElD,IAAI,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACnD,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEjC,mFAAmF;IACnF,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,+DAA+D;IAC/D,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;AACnF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,UAAkB,EAAE,YAAoB;IAC5D,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEzE,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAE/C,gFAAgF;IAChF,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAE/C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE7B,IAAI,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7D,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEpC,OAAO,SAAS,CAAC;AACrB,CAAC"}
package/src/cipher.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
2
+
3
+ // Configuración del algoritmo estándar de la industria (AES-256 en modo GCM)
4
+ const ALGORITHM = 'aes-256-gcm';
5
+ const IV_LENGTH = 12; // Vector de inicialización para GCM
6
+ const SALT_LENGTH = 16;
7
+
8
+ /**
9
+ * 1. Encriptar texto plano usando una frase maestra
10
+ */
11
+ export function encrypt(text: string, secretPhrase: string): string {
12
+ // Generar un salt y un IV aleatorios por cada encriptación para máxima seguridad
13
+ const salt = randomBytes(SALT_LENGTH);
14
+ const iv = randomBytes(IV_LENGTH);
15
+
16
+ // Derivar una llave segura de 32 bytes (256 bits) a partir de la frase del usuario
17
+ const key = scryptSync(secretPhrase, salt, 32);
18
+
19
+ const cipher = createCipheriv(ALGORITHM, key, iv);
20
+
21
+ let encrypted = cipher.update(text, 'utf8', 'hex');
22
+ encrypted += cipher.final('hex');
23
+
24
+ // Obtener el tag de autenticación (GCM asegura que el contenido no sea manipulado)
25
+ const authTag = cipher.getAuthTag().toString('hex');
26
+
27
+ // Empaquetar todo en una sola cadena para fácil almacenamiento
28
+ return `${salt.toString('hex')}:${iv.toString('hex')}:${authTag}:${encrypted}`;
29
+ }
30
+
31
+ /**
32
+ * 2. Desencriptar el bloque asegurando la integridad
33
+ */
34
+ export function decrypt(cipherText: string, secretPhrase: string): string {
35
+ const [saltHex, ivHex, authTagHex, encryptedHex] = cipherText.split(':');
36
+
37
+ if (!saltHex || !ivHex || !authTagHex || !encryptedHex) {
38
+ throw new Error('El formato del texto cifrado es inválido.');
39
+ }
40
+
41
+ const salt = Buffer.from(saltHex, 'hex');
42
+ const iv = Buffer.from(ivHex, 'hex');
43
+ const authTag = Buffer.from(authTagHex, 'hex');
44
+
45
+ // Derivar exactamente la misma llave usando la frase maestra y el salt original
46
+ const key = scryptSync(secretPhrase, salt, 32);
47
+
48
+ const decipher = createDecipheriv(ALGORITHM, key, iv);
49
+ decipher.setAuthTag(authTag);
50
+
51
+ let decrypted = decipher.update(encryptedHex, 'hex', 'utf8');
52
+ decrypted += decipher.final('utf8');
53
+
54
+ return decrypted;
55
+ }
@@ -0,0 +1,9 @@
1
+ interface PasswordResult {
2
+ password: string;
3
+ entropy: number;
4
+ level: 'DEBIL' | 'MEDIA' | 'FUERTE' | 'MILITAR';
5
+ }
6
+ export declare function calculateEntropy(password: string): number;
7
+ export declare function generateSecurePassword(length?: number): PasswordResult;
8
+ export {};
9
+ //# sourceMappingURL=entropy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["entropy.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;CACnD;AAGD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzD;AAWD,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,MAAW,GAAG,cAAc,CAsC1E"}
package/src/entropy.js ADDED
@@ -0,0 +1,62 @@
1
+ import { randomInt } from 'node:crypto';
2
+ // 1. Calcular la entropía matemática real
3
+ export function calculateEntropy(password) {
4
+ let poolSize = 0;
5
+ if (/[a-z]/.test(password))
6
+ poolSize += 26;
7
+ if (/[A-Z]/.test(password))
8
+ poolSize += 26;
9
+ if (/[0-9]/.test(password))
10
+ poolSize += 10;
11
+ if (/[^a-zA-Z0-9]/.test(password))
12
+ poolSize += 32; // Símbolos especiales
13
+ if (poolSize === 0 || password.length === 0)
14
+ return 0;
15
+ // Fórmula: L * log2(R)
16
+ return parseFloat((password.length * Math.log2(poolSize)).toFixed(2));
17
+ }
18
+ // 2. Determinar el nivel de seguridad basado en los bits de entropía
19
+ function getSecurityLevel(entropy) {
20
+ if (entropy < 40)
21
+ return 'DEBIL';
22
+ if (entropy < 60)
23
+ return 'MEDIA';
24
+ if (entropy < 80)
25
+ return 'FUERTE';
26
+ return 'MILITAR';
27
+ }
28
+ // 3. Generador criptográficamente seguro usando hardware (crypto nativo)
29
+ export function generateSecurePassword(length = 16) {
30
+ const chars = {
31
+ upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
32
+ lower: 'abcdefghijklmnopqrstuvwxyz',
33
+ digits: '0123456789',
34
+ symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?'
35
+ };
36
+ const allChars = chars.upper + chars.lower + chars.digits + chars.symbols;
37
+ const passwordChars = [];
38
+ // Asegurar que al menos tenga uno de cada tipo para evitar debilidad
39
+ passwordChars.push(chars.upper[randomInt(chars.upper.length)]);
40
+ passwordChars.push(chars.lower[randomInt(chars.lower.length)]);
41
+ passwordChars.push(chars.digits[randomInt(chars.digits.length)]);
42
+ passwordChars.push(chars.symbols[randomInt(chars.symbols.length)]);
43
+ // Llenar el resto de la longitud de forma aleatoria segura
44
+ for (let i = passwordChars.length; i < length; i++) {
45
+ passwordChars.push(allChars[randomInt(allChars.length)]);
46
+ }
47
+ // Mezclar los caracteres para romper el orden del inicio (Fisher-Yates)
48
+ for (let i = passwordChars.length - 1; i > 0; i--) {
49
+ const j = randomInt(i + 1);
50
+ const temp = passwordChars[i];
51
+ passwordChars[i] = passwordChars[j];
52
+ passwordChars[j] = temp;
53
+ }
54
+ const password = passwordChars.join('');
55
+ const entropy = calculateEntropy(password);
56
+ return {
57
+ password,
58
+ entropy,
59
+ level: getSecurityLevel(entropy)
60
+ };
61
+ }
62
+ //# sourceMappingURL=entropy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy.js","sourceRoot":"","sources":["entropy.ts"],"names":[],"mappings":"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"}
package/src/entropy.ts ADDED
@@ -0,0 +1,70 @@
1
+ import { randomInt } from 'node:crypto';
2
+
3
+ interface PasswordResult {
4
+ password: string;
5
+ entropy: number;
6
+ level: 'DEBIL' | 'MEDIA' | 'FUERTE' | 'MILITAR';
7
+ }
8
+
9
+ // 1. Calcular la entropía matemática real
10
+ export function calculateEntropy(password: string): number {
11
+ let poolSize = 0;
12
+ if (/[a-z]/.test(password)) poolSize += 26;
13
+ if (/[A-Z]/.test(password)) poolSize += 26;
14
+ if (/[0-9]/.test(password)) poolSize += 10;
15
+ if (/[^a-zA-Z0-9]/.test(password)) poolSize += 32; // Símbolos especiales
16
+
17
+ if (poolSize === 0 || password.length === 0) return 0;
18
+
19
+ // Fórmula: L * log2(R)
20
+ return parseFloat((password.length * Math.log2(poolSize)).toFixed(2));
21
+ }
22
+
23
+ // 2. Determinar el nivel de seguridad basado en los bits de entropía
24
+ function getSecurityLevel(entropy: number): 'DEBIL' | 'MEDIA' | 'FUERTE' | 'MILITAR' {
25
+ if (entropy < 40) return 'DEBIL';
26
+ if (entropy < 60) return 'MEDIA';
27
+ if (entropy < 80) return 'FUERTE';
28
+ return 'MILITAR';
29
+ }
30
+
31
+ // 3. Generador criptográficamente seguro usando hardware (crypto nativo)
32
+ export function generateSecurePassword(length: number = 16): PasswordResult {
33
+ const chars = {
34
+ upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
35
+ lower: 'abcdefghijklmnopqrstuvwxyz',
36
+ digits: '0123456789',
37
+ symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?'
38
+ };
39
+
40
+ const allChars = chars.upper + chars.lower + chars.digits + chars.symbols;
41
+ const passwordChars: string[] = [];
42
+
43
+ // Asegurar que al menos tenga uno de cada tipo para evitar debilidad
44
+ passwordChars.push(chars.upper[randomInt(chars.upper.length)]!);
45
+ passwordChars.push(chars.lower[randomInt(chars.lower.length)]!);
46
+ passwordChars.push(chars.digits[randomInt(chars.digits.length)]!);
47
+ passwordChars.push(chars.symbols[randomInt(chars.symbols.length)]!);
48
+
49
+ // Llenar el resto de la longitud de forma aleatoria segura
50
+ for (let i = passwordChars.length; i < length; i++) {
51
+ passwordChars.push(allChars[randomInt(allChars.length)]!);
52
+ }
53
+
54
+ // Mezclar los caracteres para romper el orden del inicio (Fisher-Yates)
55
+ for (let i = passwordChars.length - 1; i > 0; i--) {
56
+ const j = randomInt(i + 1);
57
+ const temp = passwordChars[i]!;
58
+ passwordChars[i] = passwordChars[j]!;
59
+ passwordChars[j] = temp;
60
+ }
61
+
62
+ const password = passwordChars.join('');
63
+ const entropy = calculateEntropy(password);
64
+
65
+ return {
66
+ password,
67
+ entropy,
68
+ level: getSecurityLevel(entropy)
69
+ };
70
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":""}
package/src/index.js ADDED
@@ -0,0 +1,65 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { generateSecurePassword } from './entropy.js';
3
+ import { encrypt, decrypt } from './cipher.js';
4
+ const rl = createInterface({
5
+ input: process.stdin,
6
+ output: process.stdout
7
+ });
8
+ function showMenu() {
9
+ console.log('\n==================================================');
10
+ console.log(' 🛡️ GUARDIÁN CRIPTOGRÁFICO v1.0 🛡️');
11
+ console.log('==================================================');
12
+ console.log('1. Generar Contraseña Militar (Cálculo de Entropía)');
13
+ console.log('2. Encriptar Credenciales o Texto (AES-256-GCM)');
14
+ console.log('3. Desencriptar Bloque Seguro');
15
+ console.log('4. Salir del Sistema');
16
+ console.log('==================================================');
17
+ rl.question('⚡ Selecciona una operación [1-4]: ', (choice) => {
18
+ switch (choice.trim()) {
19
+ case '1':
20
+ rl.question('\n🔑 Longitud deseada (Enter para 16): ', (len) => {
21
+ const length = len ? parseInt(len) : 16;
22
+ const res = generateSecurePassword(length);
23
+ console.log(`\n✅ Generada: \x1b[32m${res.password}\x1b[0m`);
24
+ console.log(`📊 Entropía: ${res.entropy} bits [${res.level}]`);
25
+ showMenu();
26
+ });
27
+ break;
28
+ case '2':
29
+ rl.question('\n📝 Introduce el texto secreto o .env: ', (text) => {
30
+ rl.question('🔐 Introduce la frase maestra de cifrado: ', (phrase) => {
31
+ const encrypted = encrypt(text, phrase);
32
+ console.log('\n📦 \x1b[33mBloque Cifrado Seguro:\x1b[0m');
33
+ console.log(`\x1b[36m${encrypted}\x1b[0m`);
34
+ showMenu();
35
+ });
36
+ });
37
+ break;
38
+ case '3':
39
+ rl.question('\n📦 Pega el bloque cifrado (salt:iv:tag:text): ', (cipherText) => {
40
+ rl.question('🔐 Introduce la frase maestra para descifrar: ', (phrase) => {
41
+ try {
42
+ const decrypted = decrypt(cipherText.trim(), phrase);
43
+ console.log(`\n✨ \x1b[32mTexto Recuperado Exitosamente:\x1b[0m\n${decrypted}`);
44
+ }
45
+ catch (err) {
46
+ console.log('\n❌ \x1b[31mError:\x1b[0m Llave incorrecta o bloque manipulado.');
47
+ }
48
+ showMenu();
49
+ });
50
+ });
51
+ break;
52
+ case '4':
53
+ console.log('\n🔒 Cerrando búnker. Conexión segura terminada.');
54
+ rl.close();
55
+ break;
56
+ default:
57
+ console.log('\n❌ Opción no válida.');
58
+ showMenu();
59
+ break;
60
+ }
61
+ });
62
+ }
63
+ // Iniciar la CLI
64
+ showMenu();
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
package/src/index.ts ADDED
@@ -0,0 +1,71 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { generateSecurePassword } from './entropy.js';
3
+ import { encrypt, decrypt } from './cipher.js';
4
+
5
+ const rl = createInterface({
6
+ input: process.stdin,
7
+ output: process.stdout
8
+ });
9
+
10
+ function showMenu() {
11
+ console.log('\n==================================================');
12
+ console.log(' 🛡️ GUARDIÁN CRIPTOGRÁFICO v1.0 🛡️');
13
+ console.log('==================================================');
14
+ console.log('1. Generar Contraseña Militar (Cálculo de Entropía)');
15
+ console.log('2. Encriptar Credenciales o Texto (AES-256-GCM)');
16
+ console.log('3. Desencriptar Bloque Seguro');
17
+ console.log('4. Salir del Sistema');
18
+ console.log('==================================================');
19
+
20
+ rl.question('⚡ Selecciona una operación [1-4]: ', (choice) => {
21
+ switch (choice.trim()) {
22
+ case '1':
23
+ rl.question('\n🔑 Longitud deseada (Enter para 16): ', (len) => {
24
+ const length = len ? parseInt(len) : 16;
25
+ const res = generateSecurePassword(length);
26
+ console.log(`\n✅ Generada: \x1b[32m${res.password}\x1b[0m`);
27
+ console.log(`📊 Entropía: ${res.entropy} bits [${res.level}]`);
28
+ showMenu();
29
+ });
30
+ break;
31
+
32
+ case '2':
33
+ rl.question('\n📝 Introduce el texto secreto o .env: ', (text) => {
34
+ rl.question('🔐 Introduce la frase maestra de cifrado: ', (phrase) => {
35
+ const encrypted = encrypt(text, phrase);
36
+ console.log('\n📦 \x1b[33mBloque Cifrado Seguro:\x1b[0m');
37
+ console.log(`\x1b[36m${encrypted}\x1b[0m`);
38
+ showMenu();
39
+ });
40
+ });
41
+ break;
42
+
43
+ case '3':
44
+ rl.question('\n📦 Pega el bloque cifrado (salt:iv:tag:text): ', (cipherText) => {
45
+ rl.question('🔐 Introduce la frase maestra para descifrar: ', (phrase) => {
46
+ try {
47
+ const decrypted = decrypt(cipherText.trim(), phrase);
48
+ console.log(`\n✨ \x1b[32mTexto Recuperado Exitosamente:\x1b[0m\n${decrypted}`);
49
+ } catch (err) {
50
+ console.log('\n❌ \x1b[31mError:\x1b[0m Llave incorrecta o bloque manipulado.');
51
+ }
52
+ showMenu();
53
+ });
54
+ });
55
+ break;
56
+
57
+ case '4':
58
+ console.log('\n🔒 Cerrando búnker. Conexión segura terminada.');
59
+ rl.close();
60
+ break;
61
+
62
+ default:
63
+ console.log('\n❌ Opción no válida.');
64
+ showMenu();
65
+ break;
66
+ }
67
+ });
68
+ }
69
+
70
+ // Iniciar la CLI
71
+ showMenu();
package/tsconfig.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ // Visit https://aka.ms/tsconfig to read more about this file
3
+ "compilerOptions": {
4
+ // File Layout
5
+ // "rootDir": "./src",
6
+ // "outDir": "./dist",
7
+
8
+ // Environment Settings
9
+ // See also https://aka.ms/tsconfig/module
10
+ "module": "nodenext",
11
+ "target": "esnext",
12
+ "types": ["node"],
13
+ // For nodejs:
14
+ // "lib": ["esnext"],
15
+ // "types": ["node"],
16
+ // and npm install -D @types/node
17
+
18
+ // Other Outputs
19
+ "sourceMap": true,
20
+ "declaration": true,
21
+ "declarationMap": true,
22
+
23
+ // Stricter Typechecking Options
24
+ "noUncheckedIndexedAccess": true,
25
+ "exactOptionalPropertyTypes": true,
26
+
27
+ // Style Options
28
+ // "noImplicitReturns": true,
29
+ // "noImplicitOverride": true,
30
+ // "noUnusedLocals": true,
31
+ // "noUnusedParameters": true,
32
+ // "noFallthroughCasesInSwitch": true,
33
+ // "noPropertyAccessFromIndexSignature": true,
34
+
35
+ // Recommended Options
36
+ "strict": true,
37
+ "jsx": "react-jsx",
38
+ "verbatimModuleSyntax": true,
39
+ "isolatedModules": true,
40
+ "noUncheckedSideEffectImports": true,
41
+ "moduleDetection": "force",
42
+ "skipLibCheck": true,
43
+ }
44
+ }