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 +2 -0
- package/README.md +87 -0
- package/package.json +18 -0
- package/src/cipher.d.ts +9 -0
- package/src/cipher.d.ts.map +1 -0
- package/src/cipher.js +42 -0
- package/src/cipher.js.map +1 -0
- package/src/cipher.ts +55 -0
- package/src/entropy.d.ts +9 -0
- package/src/entropy.d.ts.map +1 -0
- package/src/entropy.js +62 -0
- package/src/entropy.js.map +1 -0
- package/src/entropy.ts +70 -0
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +65 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +71 -0
- package/tsconfig.json +44 -0
package/.npmrc
ADDED
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
|
+
}
|
package/src/cipher.d.ts
ADDED
|
@@ -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
|
+
}
|
package/src/entropy.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
package/src/index.js.map
ADDED
|
@@ -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
|
+
}
|