Created
March 28, 2025 21:43
-
-
Save philpem/88f39140b1a42620f257f3a7e53ff9e6 to your computer and use it in GitHub Desktop.
MPT1327/MPT1343 Check Byte calculation
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
// This code takes the Electronic Serial Number (ESN) of an MPT1327 radio and calculates the 8-bit Check Byte | |
// as defined in MPT1343 section 7. | |
// This algorithm was formerly secret - one would have to ask the Radiocommunications Agency for a copy. | |
// | |
// The original intent was to stop radios from being illicitly cloned using only tha information on the label. | |
// Unfortunately the radio transmits the check byte (the whole thing) as part of the network registration sequence, | |
// so it does precisely nothing if you can sniff a radio registraion request on the control uplink channel. | |
// | |
// These days it's of historical interest, or of interest to people who are curious about MPT1327/MPT1343 (or whether | |
// their fellow hams have figured out how to change their radios' ESNs... if you know any hams using MPT/Taitnet kit) | |
// | |
// This was reverse-engineered from the Waris Labtool "ESN Tool". It might be the RA algorithm, it might not. | |
// But it probably is. | |
// | |
// This code has been cleaned up significantly. It seems to generate reasonable results, but I don't have many | |
// ESN/CHK pairs to test with. YMMV. | |
// | |
#include <stdio.h> | |
typedef int BIT; | |
void BitClear(BIT *b, size_t nbits) | |
{ | |
for (size_t i=0; i<nbits; i++) { | |
b[i] = 0; | |
} | |
} | |
void IntToBits(unsigned int val, size_t nbits, BIT *b) | |
{ | |
if (nbits > 0) { | |
BIT *p = b + nbits; | |
do { | |
*(--p) = val & 1; | |
val /= 2; | |
} while ((--nbits) > 0); | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
if (argc < 2) { | |
fprintf(stderr, "Syntax: %s manuf/model/serial\n", argv[0]); | |
return -1; | |
} | |
unsigned int manufacturer, model, serial; | |
if (sscanf(argv[1], "%u/%u/%u", &manufacturer, &model, &serial) != 3) { | |
fprintf(stderr, "ERROR: Bad ESN. Should be mm/rrr/sssss format.\n"); | |
return -2; | |
} | |
if (manufacturer > 255) { | |
fprintf(stderr, "ERROR: ESN manufacturer byte out of range (range 0-255, got %u)\n", manufacturer); | |
return -3; | |
} | |
if (model > 15) { | |
fprintf(stderr, "ERROR: ESN radio model nibble out of range (range 0-15, got %u)\n", model); | |
return -4; | |
} | |
if (serial >= (1<<18)) { | |
fprintf(stderr, "ERROR: ESN serial number part out of range (range 0-262143, got %u)\n", serial); | |
return -5; | |
} | |
BIT bitbuf[38]; | |
BIT chkbits[8]; | |
// Clear the buffers | |
BitClear(bitbuf, 38); | |
BitClear(chkbits, 8); | |
// Expand manufacturer, model and serial number into bits | |
IntToBits(manufacturer, 8, bitbuf); | |
IntToBits(model, 4, &bitbuf[8]); | |
IntToBits(serial, 18, &bitbuf[12]); | |
// Calculate check bits | |
for (size_t i=0; i<38; i++) { | |
unsigned int newBit7; | |
newBit7 = chkbits[7] ^ chkbits[6]; | |
chkbits[6] = chkbits[7] ^ chkbits[5]; | |
chkbits[5] = chkbits[4]; | |
chkbits[4] = chkbits[3]; | |
chkbits[3] = chkbits[2]; | |
chkbits[2] = chkbits[1]; | |
chkbits[1] = chkbits[0]; | |
chkbits[0] = chkbits[7] ^ bitbuf[i]; | |
chkbits[7] = newBit7; | |
} | |
unsigned char check = 0; | |
for (int i=7; i>=0; i--) { | |
check = (check * 2) | chkbits[i]; | |
} | |
check = (check + 0xC4) ^ 0x5D; | |
printf("Check byte = %u\n", check); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment