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 (119 loc) 4.9 kB
// Yes i put ultra because i had lots of ideas for this one and yeah import yargs from 'yargs/yargs'; import { hideBin } from 'yargs/helpers'; import fs from 'fs'; import crypto from 'crypto'; class SPAKE2 { constructor(password, salt = crypto.randomBytes(16), curve = 'secp256k1') { this.password = password; this.salt = salt; this.curve = curve; } deriveKey(iterations = 100000) { return crypto.scryptSync(this.password, this.salt, 32, { N: iterations }); } generateKeyPair() { const ecdh = crypto.createECDH(this.curve); ecdh.generateKeys(); return { privateKey: ecdh.getPrivateKey('hex'), publicKey: ecdh.getPublicKey('hex') }; } computeSharedSecret(peerPublicKey) { const ecdh = crypto.createECDH(this.curve); ecdh.setPrivateKey(this.deriveKey()); return ecdh.computeSecret(Buffer.from(peerPublicKey, 'hex')).toString('hex'); } encryptMessage(message, sharedSecret) { const key = crypto.createHash('sha256').update(sharedSecret).digest(); const nonce = crypto.randomBytes(12); const aesgcm = crypto.createCipheriv('aes-256-gcm', key, nonce); const encrypted = Buffer.concat([aesgcm.update(message, 'utf8'), aesgcm.final()]); return Buffer.concat([nonce, aesgcm.getAuthTag(), encrypted]).toString('hex'); } verifyChallenge(peerPublicKey, challenge) { const derivedSecret = this.computeSharedSecret(peerPublicKey); return crypto.createHash('sha256').update(derivedSecret).digest('hex') === challenge; } saveKeysToFile(filename, keys) { fs.writeFileSync(filename, JSON.stringify(keys, null, 2)); } loadKeysFromFile(filename) { return JSON.parse(fs.readFileSync(filename)); } } // CLI Setup async function main() { const argv = yargs(hideBin(process.argv)) .option('mode', { alias: 'm', type: 'string', choices: ['keygen', 'exchange', 'encrypt', 'verify'], describe: 'Generate keys, exchange secrets, encrypt messages, or verify challenges', }) .option('password', { alias: 'p', type: 'string', demandOption: true, describe: 'Shared password for authentication', }) .option('peerKey', { alias: 'k', type: 'string', describe: 'Peer public key for key exchange or verification', }) .option('message', { alias: 'msg', type: 'string', describe: 'Message to encrypt', }) .option('challenge', { alias: 'c', type: 'string', describe: 'Verification challenge hash', }) .option('curve', { alias: 'curve', type: 'string', choices: ['secp256k1', 'prime256v1', 'ed25519'], default: 'secp256k1', describe: 'Cryptographic curve for key exchange', }) .help() .argv; const spake2 = new SPAKE2(argv.password, undefined, argv.curve); if (argv.mode === 'keygen') { const keys = spake2.generateKeyPair(); console.log(`✅ Generated SPAKE2 Key Pair`); console.log(`🔑 Private Key: ${keys.privateKey}`); console.log(`📡 Public Key: ${keys.publicKey}`); spake2.saveKeysToFile('spake2_keys.json', keys); } else if (argv.mode === 'exchange') { if (!argv.peerKey) { console.error("❌ Key exchange requires a peer public key"); return; } const sharedSecret = spake2.computeSharedSecret(argv.peerKey); console.log(`🔐 Shared Secret: ${sharedSecret}`); } else if (argv.mode === 'encrypt') { if (!argv.message || !argv.peerKey) { console.error("❌ Encryption requires a message and a peer key"); return; } const sharedSecret = spake2.computeSharedSecret(argv.peerKey); const encryptedMessage = spake2.encryptMessage(argv.message, sharedSecret); console.log(`🔐 Encrypted Message (Hex): ${encryptedMessage}`); } else if (argv.mode === 'verify') { if (!argv.peerKey || !argv.challenge) { console.error("❌ Verification requires a peer key and challenge"); return; } const isValid = spake2.verifyChallenge(argv.peerKey, argv.challenge); console.log(isValid ? "✅ Challenge verified successfully!" : "❌ Challenge verification failed."); } else { console.error("❌ Invalid mode. Use --mode keygen | exchange | encrypt | verify"); } } console.log("🚀 Debug: Running main function..."); main();