const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const PHONETIC = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform', 'Victor', 'Whiskey', 'Xray', 'Yankee', 'Zulu']; class SeededRandom { constructor(seed) { this.seed = seed; this.counter = 0; } next() { const hash = CryptoJS.SHA256(this.seed + ':' + this.counter); this.counter++; const hex = hash.toString(CryptoJS.enc.Hex); return parseInt(hex.substring(0, 8), 16) / 0xFFFFFFFF; } nextInt(min, max) { return Math.floor(this.next() * (max - min)) + min; } choice(arr) { return arr[this.nextInt(0, arr.length)]; } } function generateHOTP(secret, nonce) { const rng = new SeededRandom(secret + ':hotp:' + nonce); let code = ''; for (let i = 0; i < 2; i++) { code += rng.choice(CHARS.split('')); } return code; } function generateAuthTable(seed, tableIndex) { const rng = new SeededRandom(seed + ':table:' + tableIndex); const rows = 'NOPQRSTUVWXYZ'.split(''); const cols = 'ABCDEFGHIJKLM'.split(''); const table = []; for (let row of rows) { const rowData = []; for (let col of cols) { rowData.push(rng.choice(CHARS.split(''))); } table.push(rowData); } return table; } function generatePad(seed, padKey, length = 60) { const rng = new SeededRandom(seed + ':pad:' + padKey); const pad = []; for (let i = 0; i < length; i++) { pad.push(rng.nextInt(0, 1000)); } return pad; } function generatePadDisplay(seed, padKey) { const rng = new SeededRandom(seed + ':pad:' + padKey); const groups = []; for (let i = 0; i < 24; i++) { const num = rng.nextInt(0, 1000).toString().padStart(3, '0'); groups.push(num); } return groups.join(' '); } function encodeMessage(message, key, padKey, useStream = true) { const messageBytes = new TextEncoder().encode(message); const padLength = useStream ? messageBytes.length : 60; const pad = generatePad(key, padKey, padLength); const encoded = []; for (let i = 0; i < messageBytes.length; i++) { const padValue = pad[i % pad.length]; const result = (messageBytes[i] + padValue) % 1000; encoded.push(result.toString().padStart(3, '0')); } return encoded.join(''); } function decodeMessage(encoded, key, padKey, useStream = true) { const values = []; for (let i = 0; i < encoded.length; i += 3) { values.push(parseInt(encoded.substr(i, 3), 10)); } const padLength = useStream ? values.length : 60; const pad = generatePad(key, padKey, padLength); const decoded = []; for (let i = 0; i < values.length; i++) { const padValue = pad[i % pad.length]; let result = (values[i] - padValue) % 1000; if (result < 0) result += 1000; decoded.push(result); } return new TextDecoder().decode(new Uint8Array(decoded)); }