mirror of
https://github.com/planetrenox/inzerosight.git
synced 2026-09-18 18:15:42 +00:00
Use 11-character signatures and detect headers across WBR
This commit is contained in:
74
sig.js
74
sig.js
@@ -9,6 +9,7 @@ export const SIG = {
|
||||
};
|
||||
|
||||
export const CIPHERS = {
|
||||
0: 'PLAIN',
|
||||
1: 'SPECK48_96CTR',
|
||||
2: 'SPECK32_64ECB (insecure)'
|
||||
};
|
||||
@@ -17,36 +18,59 @@ export const CIPHER_TO_ID = Object.fromEntries(
|
||||
Object.entries(CIPHERS).map(([k, v]) => [v, +k])
|
||||
);
|
||||
|
||||
const SIGNATURES = Object.entries(SIG).flatMap(([base, prefix]) =>
|
||||
Object.entries(CIPHERS).map(([id, cipher]) => {
|
||||
const digits = (+id).toString(base).padStart(4, '0');
|
||||
if (digits.length !== 4) throw new RangeError(`Cipher ID ${id} exceeds ZWUS-${base}'s signature capacity`);
|
||||
const sig = prefix + zwus[base].unifier + zwus[base][0] +
|
||||
Array.from(digits, d => zwus[base][d]).join('');
|
||||
if (sig.length !== 11) throw new RangeError('Signatures must contain exactly 11 characters');
|
||||
return { base, cipher, sig, legacy: false };
|
||||
})
|
||||
);
|
||||
|
||||
export function makeSig(base, cipher) {
|
||||
let s = SIG[base];
|
||||
const id = CIPHER_TO_ID[cipher];
|
||||
if (id) {
|
||||
const zwDigits = Array.from(id.toString(base).padStart(3, '0'), d => zwus[base][d]).join('');
|
||||
s += zwus[base].unifier + zwus[base][0] + zwDigits;
|
||||
}
|
||||
return s;
|
||||
const entry = SIGNATURES.find(s => s.base === String(base) && s.cipher === cipher);
|
||||
if (!entry) throw new RangeError(`Unsupported signature: ZWUS-${base}, ${cipher}`);
|
||||
return entry.sig;
|
||||
}
|
||||
|
||||
export function parseSig(text) {
|
||||
let sigIdx = text.indexOf(SIG_PREFIX), base;
|
||||
function findSig(text, signatures) {
|
||||
let sigIdx = text.indexOf(SIG_PREFIX);
|
||||
while (sigIdx !== -1) {
|
||||
base = Object.keys(SIG).find(b => text.startsWith(SIG[b], sigIdx));
|
||||
if (base) break;
|
||||
sigIdx = text.indexOf(SIG_PREFIX, sigIdx + SIG_PREFIX.length);
|
||||
const entry = signatures.find(s => text.startsWith(s.sig, sigIdx) &&
|
||||
(!s.legacyPlain || text[sigIdx + s.sig.length] !== zwus[s.base].unifier));
|
||||
if (entry) {
|
||||
const { base, cipher, sig, legacy } = entry;
|
||||
return { base, cipher, payload: text.slice(sigIdx + sig.length), sigIdx, sigLen: sig.length, legacy };
|
||||
}
|
||||
sigIdx = text.indexOf(SIG_PREFIX, sigIdx + 1);
|
||||
}
|
||||
if (!base) return null;
|
||||
const after = text.slice(sigIdx + SIG[base].length);
|
||||
const barrier = zwus[base].unifier + zwus[base][0];
|
||||
if (after.startsWith(barrier)) {
|
||||
const zwDigits = Array.from(after.slice(barrier.length, barrier.length + 3));
|
||||
const digits = zwDigits.map(z => Object.keys(zwus[base]).find(k => zwus[base][k] === z)).join('');
|
||||
const cipher = CIPHERS[parseInt(digits, base)];
|
||||
if (!cipher) return { base, cipher: 'PLAIN', payload: after, sigIdx, sigLen: SIG[base].length };
|
||||
const payload = after.slice(barrier.length + 3);
|
||||
const sigLen = SIG[base].length + barrier.length + 3;
|
||||
return { base, cipher, payload, sigIdx, sigLen };
|
||||
}
|
||||
return { base, cipher: 'PLAIN', payload: after, sigIdx, sigLen: SIG[base].length };
|
||||
return null;
|
||||
}
|
||||
|
||||
// Current format: match only complete, registered 11-character signatures.
|
||||
export const parseModernSig = text => findSig(text, SIGNATURES);
|
||||
|
||||
// Legacy compatibility: remove this registry, reader, and parseSig fallback together.
|
||||
// Keep the supported bases and cipher IDs frozen; future standards use only the current format.
|
||||
const LEGACY_SIGNATURES = [3, 6, 7].flatMap(base => [
|
||||
...[1, 2].map(id => ({
|
||||
base: String(base), cipher: CIPHERS[id], legacy: true,
|
||||
sig: SIG[base] + zwus[base].unifier + zwus[base][0].repeat(3) + zwus[base][id]
|
||||
})),
|
||||
{ base: String(base), cipher: 'PLAIN', sig: SIG[base], legacy: true, legacyPlain: true }
|
||||
]);
|
||||
|
||||
// Legacy plaintext never starts with a unifier; do not downgrade incomplete/unknown extensions.
|
||||
export const parseLegacySig = text => findSig(text, LEGACY_SIGNATURES);
|
||||
export function parseSig(text) {
|
||||
const modern = parseModernSig(text), legacy = parseLegacySig(text);
|
||||
if (!modern) return legacy;
|
||||
// Legacy messages separated by visible text still need their own overlay.
|
||||
if (legacy && legacy.sigIdx < modern.sigIdx &&
|
||||
getPayloadEnd(text, legacy.base, legacy.sigIdx + legacy.sigLen) < modern.sigIdx) return legacy;
|
||||
return modern;
|
||||
}
|
||||
|
||||
export function getPayloadEnd(text, base, startOffset) {
|
||||
|
||||
Reference in New Issue
Block a user