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 (114 loc) 3.69 kB
import crypto from 'crypto'; import yargs from 'yargs/yargs'; import { hideBin } from 'yargs/helpers'; function padHex(hex) { return hex.length % 2 ? '0' + hex : hex; } function strToHex(str) { return Buffer.from(str, 'utf8').toString('hex'); } function intToHex64(num) { let hex = num.toString(16); hex = hex.padStart(16, '0'); return hex; } function dynamicTruncate(hmac) { const offset = hmac[hmac.length - 1] & 0xf; const binCode = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | (hmac[offset + 3] & 0xff); return binCode; } function generateOCRA({ suite, keyHex, counter, question, password, session, timestamp, digits }) { const suiteBuf = Buffer.from(suite, 'ascii'); const sep = Buffer.from([0x00]); function hexPad(hex, length) { return hex.padEnd(length * 2, '0'); } const counterBuf = counter ? Buffer.from(padHex(counter.toString(16)), 'hex') : Buffer.alloc(0); const questionBuf = question ? Buffer.from(question, 'ascii') : Buffer.alloc(0); const passwordBuf = password ? Buffer.from(password, 'ascii') : Buffer.alloc(0); const sessionBuf = session ? Buffer.from(session, 'ascii') : Buffer.alloc(0); const timestampBuf = timestamp ? Buffer.from(timestamp, 'ascii') : Buffer.alloc(0); const msg = Buffer.concat([suiteBuf, sep, counterBuf, questionBuf, passwordBuf, sessionBuf, timestampBuf]); const key = Buffer.from(keyHex, 'hex'); const hmac = crypto.createHmac('sha1', key).update(msg).digest(); const binCode = dynamicTruncate(hmac); const otp = (binCode % 10 ** digits).toString().padStart(digits, '0'); return otp; } async function main() { const argv = yargs(hideBin(process.argv)) .option('key', { alias: 'k', type: 'string', demandOption: true, describe: 'Secret key (hex string)' }) .option('suite', { alias: 's', type: 'string', default: 'OCRA-1:HOTP-SHA1-6:QN08', describe: 'OCRA suite string (default: "OCRA-1:HOTP-SHA1-6:QN08")' }) .option('counter', { alias: 'c', type: 'string', default: '', describe: 'Counter value (hex string or decimal number)' }) .option('question', { alias: 'q', type: 'string', default: '', describe: 'Challenge question (usually numeric string)' }) .option('password', { alias: 'p', type: 'string', default: '', describe: 'Password or PIN' }) .option('session', { alias: 'S', type: 'string', default: '', describe: 'Session information' }) .option('timestamp', { alias: 't', type: 'string', default: '', describe: 'Timestamp value' }) .option('digits', { alias: 'd', type: 'number', default: 6, describe: 'Number of digits in OTP' }) .argv; try { let counterHex = argv.counter; if (counterHex && !counterHex.startsWith('0x') && /^\d+$/.test(counterHex)) { counterHex = BigInt(argv.counter).toString(16); } const otp = generateOCRA({ suite: argv.suite, keyHex: argv.key, counter: counterHex, question: argv.question, password: argv.password, session: argv.session, timestamp: argv.timestamp, digits: argv.digits, }); console.log(`✅ OCRA OTP (${argv.digits} digits):`, otp); } catch (err) { console.error('❌ OCRA generation failed:', err.message); } } console.log('🚀 Running OCRA generator CLI...'); main();