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
JavaScript
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();