Last active
June 30, 2026 09:54
-
-
Save Webbanditten/30196d2d6d324030671895e19218535a to your computer and use it in GitHub Desktop.
Dinec Wiegand encoding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Dinec Wiegand encoding: EM4100 RFID -> "Chip system" badge id (Badge1). | |
| * | |
| * Use to enroll chips from a web dashboard instead of Dinec's software. | |
| * Take the decimal RFID a scanner reads, produce the hex value Dinec stores | |
| * in [DBM6000].[dbo].[Users].[Badge1] (CardType1 = EM4100). Write that, done. | |
| * | |
| * NOT encryption. Reversible encoding = bit-reversal of RFID's low 24 bits, | |
| * framed as 26-bit Wiegand with inverted parity (lead odd / trail even). | |
| * Reverse-engineered from 25 known pairs, 100% match. RFID bits above bit23 | |
| * (the 371.../361... manufacturer prefix) are discarded. | |
| */ | |
| function parity(x) { | |
| let p = 0; | |
| while (x) { p ^= x & 1; x >>>= 1; } | |
| return p; | |
| } | |
| function rev24(x) { | |
| let r = 0; | |
| for (let i = 0; i < 24; i++) r = (r << 1) | ((x >>> i) & 1); | |
| return r >>> 0; | |
| } | |
| /** | |
| * Encode a scanned EM4100 RFID into the Dinec chip id (numeric). | |
| * @param {number} rfid - decimal RFID from the scanner (e.g. 371045138) | |
| * @returns {number} 26-bit chip id (e.g. 0x2919B71) | |
| */ | |
| function encode(rfid) { | |
| const payload = rev24(rfid & 0xFFFFFF); // chip bits 24..1 | |
| const pLead = parity((payload >>> 12) & 0xFFF) ^ 1; // leading = odd parity | |
| const pTrail = parity(payload & 0xFFF); // trailing = even parity | |
| return ((pLead << 25) | (payload << 1) | pTrail) >>> 0; | |
| } | |
| /** | |
| * Encode to the uppercase hex string stored in Badge1 (no leading zeros), | |
| * e.g. encodeBadge(371045138) === "2919B71". | |
| * @param {number|string} rfid - decimal RFID from the scanner | |
| * @returns {string} | |
| */ | |
| function encodeBadge(rfid) { | |
| return encode(Number(rfid)).toString(16).toUpperCase(); | |
| } | |
| // ---- self-test: node dinec_wiegand.js ---- | |
| if (typeof require !== 'undefined' && require.main === module) { | |
| const data = [ | |
| [371045138, '2919B71'], [371044110, 'E1EB70'], [371050725, '34E2770'], [371050850, '8D2770'], | |
| [371035623, '1CF6371'], [371035018, '2A3A371'], [371043008, '206AB70'], [371039417, '13A7370'], | |
| [371044608, '11B71'], [361929066, '2AD3293'], [371050019, '188C770'], [371049170, '968770'], | |
| [371043089, '111AB70'], [371042545, '31E2B70'], [371041147, '3BD8B70'], [371052071, '1C8E770'], | |
| [371048660, '2560770'], [371047717, '3497B71'], [371044847, '3EF1B71'], [371051508, '25FA770'], | |
| [371034902, '2D1A371'], [371045289, '32B9B71'], [371051072, '4A770'], [371036201, '1281370'], | |
| [2973668, '24FF568'], | |
| ]; | |
| const ok = data.every(([r, b]) => encodeBadge(r) === b); | |
| console.log(ok ? `ALL ${data.length} MATCH` : 'FAIL'); | |
| } | |
| if (typeof module !== 'undefined' && module.exports) { | |
| module.exports = { encode, encodeBadge }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment