mojic

Obfuscate C source code into e...
Log | Files | Refs | README | LICENSE

commit ec4e8a4194db059e96dd15b04a0efaf4392041e3
parent 17d70aede505b5bc55915d51332c181204cfdef7
Author: Amit Dutta <amitdutta4255@gmail.com>
Date:   Thu, 29 Jan 2026 13:22:49 +0530

v1.2.5

Diffstat:
MREADME.md | 2+-
Mbin/mojic.js | 97+++++++++++++++++++------------------------------------------------------------
Mlib/CipherEngine.js | 62++++++++++++++++++++++++++++++--------------------------------
Mnode_modules/.package-lock.json | 4++--
Mpackage-lock.json | 8++++----
Mpackage.json | 4++--
6 files changed, 62 insertions(+), 115 deletions(-)

diff --git a/README.md b/README.md @@ -1,4 +1,4 @@ -# Mojic v1.2.1 +# Mojic v1.2.5 > **Operation Polymorphic Chaos: Obfuscate C source code into a randomized, password-seeded stream of emojis.** diff --git a/bin/mojic.js b/bin/mojic.js @@ -12,7 +12,7 @@ import { CipherEngine } from '../lib/CipherEngine.js'; program .name('mojic') .description('Obfuscate C source code into emojis') - .version('1.2.2') + .version('1.2.5') .addHelpCommand('help [command]', 'Display help for command') .showHelpAfterError(); @@ -78,7 +78,6 @@ const createHeaderSkipper = () => { }); }; -// --- FLATTENING (Minifier) --- const createMinifier = () => { return new Transform({ transform(chunk, encoding, cb) { @@ -91,11 +90,8 @@ const createMinifier = () => { }); }; -// --- Recursive Logic --- - async function traverseDirectory(currentPath, extension, callback) { const entries = fs.readdirSync(currentPath, { withFileTypes: true }); - for (const entry of entries) { const fullPath = path.join(currentPath, entry.name); if (entry.isDirectory()) { @@ -123,7 +119,7 @@ program throw new Error(`'${targetPath}' is a directory. Use -r to process recursively.`); } - console.log(chalk.blue('Initiating Mojic Encryption v1.1...')); + console.log(chalk.blue('Initiating Mojic Encryption v1.2...')); if (options.flat) console.log(chalk.yellow(' -> Structural Flattening Enabled')); const password = await promptPassword('Create password for file(s):'); @@ -142,10 +138,7 @@ program await new Promise((resolve, reject) => { let pipeline = readStream; - - if (options.flat) { - pipeline = pipeline.pipe(createMinifier()); - } + if (options.flat) pipeline = pipeline.pipe(createMinifier()); pipeline .pipe(engine.getEncryptStream()) @@ -193,10 +186,7 @@ program const headerStr = await getStreamHeader(filePath); const metadata = CipherEngine.decodeHeader(headerStr); - const engine = new CipherEngine(password); - - // Pass the Auth Check Hex (if available in new format) await engine.init(metadata.saltHex, metadata.authCheckHex); const readStream = fs.createReadStream(filePath); @@ -204,8 +194,9 @@ program await new Promise((resolve, reject) => { const decryptStream = engine.getDecryptStream(); - decryptStream.on('error', (err) => { + readStream.destroy(); // Stop reading + writeStream.destroy(); // Stop writing reject(err); }); @@ -216,19 +207,12 @@ program .on('finish', resolve) .on('error', reject); }); - - return true; // Success + return true; } catch (e) { const outputName = filePath.replace(/\.mojic$/, '') + '.restored.c'; + // Wait for stream handles to release + setTimeout(() => { if (fs.existsSync(outputName)) try { fs.unlinkSync(outputName); } catch(ign){} }, 100); - // Cleanup output file on error - setTimeout(() => { - if (fs.existsSync(outputName)) { - try { fs.unlinkSync(outputName); } catch(ign){} - } - }, 100); - - // Specific Error Messaging (No Emojis) if (e.message === "WRONG_PASSWORD") { console.log(chalk.red(` Error: Incorrect Password`)); } else if (e.message === "FILE_TAMPERED") { @@ -236,8 +220,7 @@ program } else { console.log(chalk.red(` Error: ${e.message}`)); } - - return false; // Failure + return false; } }; @@ -247,9 +230,7 @@ program console.log(chalk.green('Batch decryption complete.')); } else { const success = await processFile(targetPath); - if (success) { - console.log(chalk.green(`Restored.`)); - } + if (success) console.log(chalk.green(`Restored.`)); } } catch (err) { @@ -258,7 +239,6 @@ program }); // --- SRT --- - const rotatePassword = async (file) => { try { if (!fs.existsSync(file)) throw new Error('File not found'); @@ -283,16 +263,8 @@ const rotatePassword = async (file) => { await new Promise((resolve, reject) => { const decryptStream = oldEngine.getDecryptStream(); - - decryptStream.on('error', (err) => reject(err)); - - readStream - .pipe(createHeaderSkipper()) - .pipe(decryptStream) - .pipe(newEngine.getEncryptStream()) - .pipe(writeStream) - .on('finish', resolve) - .on('error', reject); + decryptStream.on('error', reject); + readStream.pipe(createHeaderSkipper()).pipe(decryptStream).pipe(newEngine.getEncryptStream()).pipe(writeStream).on('finish', resolve).on('error', reject); }); fs.renameSync(tempFile, file); @@ -300,11 +272,8 @@ const rotatePassword = async (file) => { } catch (err) { if (fs.existsSync(file + '.tmp')) fs.unlinkSync(file + '.tmp'); - if (err.message === "WRONG_PASSWORD") { - console.error(chalk.red('Error: Incorrect Current Password')); - } else { - console.error(chalk.red('Error:'), err.message); - } + if (err.message === "WRONG_PASSWORD") console.error(chalk.red('Error: Incorrect Current Password')); + else console.error(chalk.red('Error:'), err.message); } }; @@ -331,15 +300,8 @@ const reEncrypt = async (file) => { await new Promise((resolve, reject) => { const decryptStream = oldEngine.getDecryptStream(); - decryptStream.on('error', (err) => reject(err)); - - readStream - .pipe(createHeaderSkipper()) - .pipe(decryptStream) - .pipe(newEngine.getEncryptStream()) - .pipe(writeStream) - .on('finish', resolve) - .on('error', reject); + decryptStream.on('error', reject); + readStream.pipe(createHeaderSkipper()).pipe(decryptStream).pipe(newEngine.getEncryptStream()).pipe(writeStream).on('finish', resolve).on('error', reject); }); fs.renameSync(tempFile, file); @@ -347,28 +309,15 @@ const reEncrypt = async (file) => { } catch (err) { if (fs.existsSync(file + '.tmp')) fs.unlinkSync(file + '.tmp'); - if (err.message === "WRONG_PASSWORD") { - console.error(chalk.red('Error: Incorrect Password')); - } else { - console.error(chalk.red('Error:'), err.message); - } + if (err.message === "WRONG_PASSWORD") console.error(chalk.red('Error: Incorrect Password')); + else console.error(chalk.red('Error:'), err.message); } }; -program - .command('srt') - .description('Security and Rotation Tools') - .option('--pass <file>', 'Update the password for an existing file') - .option('--re <file>', 'Re-encrypt with new random seed (Same password)') - .action(async (options) => { - if (options.pass) { - await rotatePassword(options.pass); - } else if (options.re) { - await reEncrypt(options.re); - } else { - console.log(chalk.yellow('Please specify an option: --pass <file> or --re <file>')); - program.commands.find(c => c.name() === 'srt').help(); - } - }); +program.command('srt').description('Security and Rotation Tools').option('--pass <file>', 'Update password').option('--re <file>', 'Re-encrypt').action(async (options) => { + if (options.pass) await rotatePassword(options.pass); + else if (options.re) await reEncrypt(options.re); + else { console.log(chalk.yellow('Please specify an option: --pass <file> or --re <file>')); program.commands.find(c => c.name() === 'srt').help(); } +}); program.parse(process.argv); \ No newline at end of file diff --git a/lib/CipherEngine.js b/lib/CipherEngine.js @@ -3,15 +3,12 @@ import { Transform } from 'stream'; import { StringDecoder } from 'string_decoder'; /** - * MOJIC v1.2.1 CIPHER ENGINE + * MOJIC v1.2.5 CIPHER ENGINE * "Operation Polymorphic Chaos" - * * Features: - * - Xoshiro256** PRNG (256-bit State) - * - Base-1024 Compression (5 bytes -> 4 emojis) - * - Polymorphic Keyword Encryption (Rolling Cipher) - * - HMAC-SHA256 Integrity Footer - * - Line Wrapping (New: Prevents lag in editors) - * - Instant Password Verification (New: Header Auth Check) + * * Fixes: + * - Word Boundaries: Prevents splitting variables like 'secretCode' + * - Regex: correctly handles #directives vs keywords + * - Tokenization: Handles combined graphemes (skin tones/modifiers) during decryption */ // --- EMOJI UNIVERSE GENERATION --- @@ -21,7 +18,7 @@ const generateUniverse = () => { const universe = []; const ranges = [ [0x1F600, 0x1F64F], // Emoticons - [0x1F300, 0x1F5FF], // Misc Symbols + [0x1F300, 0x1F5FF], // Misc Symbols (Contains modifiers) [0x1F680, 0x1F6FF], // Transport [0x1F900, 0x1F9FF] // Supplemental ]; @@ -158,7 +155,7 @@ export class CipherEngine { _encodeHeader() { const saltHex = this.salt.toString('hex'); - const authCheck = this.authKey.subarray(0, 4).toString('hex'); // 4 bytes check + const authCheck = this.authKey.subarray(0, 4).toString('hex'); let headerStr = ''; for (const char of (saltHex + authCheck)) { @@ -196,9 +193,12 @@ export class CipherEngine { transform(chunk, encoding, callback) { const str = chunk.toString('utf8'); - const sortedKeywords = [...C_KEYWORDS].sort((a, b) => b.length - a.length); - const keywordPattern = sortedKeywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'); - const regex = new RegExp(`(${keywordPattern})`, 'g'); + // Separate alpha keywords (int, void) from symbols (#include) + const alphaKeywords = C_KEYWORDS.filter(k => /^\w+$/.test(k)).sort((a,b)=>b.length-a.length).join('|'); + const symKeywords = C_KEYWORDS.filter(k => !/^\w+$/.test(k)).map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'); + + // Match: \b(int|void)\b OR (#include) + const regex = new RegExp(`(\\b(?:${alphaKeywords})\\b|(?:${symKeywords}))`, 'g'); const parts = str.split(regex); @@ -218,8 +218,6 @@ export class CipherEngine { const outBuf = Buffer.from(polyEmoji); engine.hmac.update(outBuf); - - // Emit wrapped this.push(engine._wrapOutput(outBuf)); } else { @@ -256,7 +254,6 @@ export class CipherEngine { footerStr += HEADER_ALPHABET[val]; } } - // Push footer (always starts on a new line or wrapped) this.push(Buffer.from('\n' + footerStr)); callback(); } @@ -289,7 +286,6 @@ export class CipherEngine { _flushDataBuffer(buf) { if (buf.length === 0) return Buffer.alloc(0); - const padded = Buffer.alloc(5); buf.copy(padded); const enc = this._encodeBase1024(padded); @@ -313,15 +309,22 @@ export class CipherEngine { const segments = [...segmenter.segment(str)]; for (const { segment } of segments) { - // Filter out whitespace/newlines used for wrapping - if (segment.match(/\s/)) continue; - - emojiBuffer.push(segment); - - if (emojiBuffer.length > FOOTER_LEN) { - const emo = emojiBuffer.shift(); - engine._processDecryptToken(emo, this); - engine.hmac.update(Buffer.from(emo)); + if (segment.match(/\s/)) continue; // Skip wraps + + // FIX: Some emojis in the universe (like skin tones 0x1F3FB) are modifiers. + // If they appear next to another emoji, Intl.Segmenter merges them. + // We must split them back into atomic code points to preserve token count. + const atoms = [...segment]; + + for (const atom of atoms) { + emojiBuffer.push(atom); + + if (emojiBuffer.length > FOOTER_LEN) { + const emo = emojiBuffer.shift(); + engine._processDecryptToken(emo, this); + // Feed actual atomic tokens to HMAC to match encryption + engine.hmac.update(Buffer.from(emo)); + } } } callback(); @@ -349,13 +352,9 @@ export class CipherEngine { } if (footerHex !== calcDigest) { - // Critical security failure this.emit('error', new Error("FILE_TAMPERED")); return; } - - if (engine.decodeDataBuf.length > 0) { - } callback(); } }); @@ -374,6 +373,7 @@ export class CipherEngine { const originalEmo = this.keywordEmojis[baseIdx]; const keyword = this.keywordReverseMap.get(originalEmo); + // Safety: This buffer should be empty if the stream is synced. if (this.decodeDataBuf.length > 0) { this.decodeDataBuf = []; } @@ -388,8 +388,6 @@ export class CipherEngine { const cleanChunk = chunk.filter(b => b !== 0x00); stream.push(cleanChunk); } - } else { - // Unknown emojis are ignored now } } diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json @@ -1,6 +1,6 @@ { - "name": "@notamitgamer/mojic", - "version": "1.2.2", + "name": "mojic", + "version": "1.2.4", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package-lock.json b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "@notamitgamer/mojic", - "version": "1.2.2", + "name": "mojic", + "version": "1.2.4", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@notamitgamer/mojic", - "version": "1.2.2", + "name": "mojic", + "version": "1.2.4", "license": "Apache-2.0", "dependencies": { "chalk": "^5.3.0", diff --git a/package.json b/package.json @@ -1,6 +1,6 @@ { - "name": "@notamitgamer/mojic", - "version": "1.2.2", + "name": "mojic", + "version": "1.2.5", "description": "Obfuscate C source code into encrypted, password-seeded emoji streams.", "main": "bin/mojic.js", "bin": {
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror