UNPKG

crypto-keygen-suite

Version:

Key generation utilities for cryptographic operations. YES I RENAMED IT. SIX STATE PROTOCOL!!! See its folder for all <3

133 lines (115 loc) 4.75 kB
import yargs from 'yargs/yargs'; import { hideBin } from 'yargs/helpers'; import crypto from 'crypto'; class NoiseProtocol { constructor() { // Generate X25519 key pair const { privateKey, publicKey } = crypto.generateKeyPairSync('x25519'); this.localPrivateKey = privateKey; // Store private key directly this.localPublicKey = publicKey.export({ type: 'spki', format: 'pem' }); // Properly export public key this.remotePublicKey = null; this.sharedSecret = null; this.symmetricKey = null; this.chainingKey = null; } setRemotePublicKey(remotePublicKey) { this.remotePublicKey = crypto.createPublicKey(remotePublicKey); } performHandshake() { if (!this.remotePublicKey) { throw new Error("❌ Remote public key not set"); } this.sharedSecret = crypto.diffieHellman({ privateKey: this.localPrivateKey, publicKey: this.remotePublicKey }); const { symmetricKey, chainingKey } = this.deriveKeys(this.sharedSecret); this.symmetricKey = symmetricKey; this.chainingKey = chainingKey; } deriveKeys(sharedSecret) { const hkdf = crypto.createHmac('sha256', sharedSecret) .update('noise protocol') .digest(); return { symmetricKey: hkdf.slice(0, 32), chainingKey: hkdf.slice(32) }; } encryptMessage(plaintext) { if (!this.symmetricKey) { throw new Error("❌ Handshake not performed"); } const nonce = crypto.randomBytes(12); const aesgcm = crypto.createCipheriv('aes-256-gcm', this.symmetricKey, nonce); const encrypted = Buffer.concat([aesgcm.update(plaintext, 'utf8'), aesgcm.final()]); return Buffer.concat([nonce, aesgcm.getAuthTag(), encrypted]).toString('hex'); } decryptMessage(encryptedHex) { if (!this.symmetricKey) { throw new Error("❌ Handshake not performed"); } const encryptedBuffer = Buffer.from(encryptedHex, 'hex'); const nonce = encryptedBuffer.slice(0, 12); const authTag = encryptedBuffer.slice(12, 28); const ciphertext = encryptedBuffer.slice(28); const aesgcm = crypto.createDecipheriv('aes-256-gcm', this.symmetricKey, nonce); aesgcm.setAuthTag(authTag); const decrypted = Buffer.concat([aesgcm.update(ciphertext), aesgcm.final()]); return decrypted.toString(); } } // CLI Setup async function main() { const argv = yargs(hideBin(process.argv)) .option('mode', { alias: 'm', type: 'string', choices: ['generate', 'handshake', 'encrypt', 'decrypt'], describe: 'Choose operation mode: generate keys, handshake, encrypt, or decrypt', }) .option('message', { alias: 'msg', type: 'string', describe: 'Message to encrypt or decrypt', }) .option('remoteKey', { alias: 'r', type: 'string', describe: 'Remote public key for handshake', }) .help() .argv; const noise = new NoiseProtocol(); if (argv.mode === 'generate') { console.log(`✅ Generated Noise Protocol Keys`); console.log(`🔑 Private Key: ${noise.localPrivateKey.export({ type: 'pkcs8', format: 'pem' })}`); console.log(`📡 Public Key: ${noise.localPublicKey}`); } else if (argv.mode === 'handshake') { if (!argv.remoteKey) { console.error("❌ Handshake requires a remote public key"); return; } noise.setRemotePublicKey(argv.remoteKey); noise.performHandshake(); console.log(`✅ Handshake completed! Shared secret derived.`); } else if (argv.mode === 'encrypt') { if (!argv.message) { console.error("❌ Encryption requires a message"); return; } const encrypted = noise.encryptMessage(argv.message); console.log(`🔐 Encrypted Message (Hex): ${encrypted}`); } else if (argv.mode === 'decrypt') { if (!argv.message) { console.error("❌ Decryption requires an encrypted message"); return; } const decrypted = noise.decryptMessage(argv.message); console.log(`📜 Decrypted Message: ${decrypted}`); } else { console.error("❌ Invalid mode. Use --mode generate | handshake | encrypt | decrypt"); } } console.log("🚀 Debug: Running main function..."); main();