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