Skip to content

Instantly share code, notes, and snippets.

@philpem
Created March 28, 2025 21:43
Show Gist options
  • Save philpem/88f39140b1a42620f257f3a7e53ff9e6 to your computer and use it in GitHub Desktop.
Save philpem/88f39140b1a42620f257f3a7e53ff9e6 to your computer and use it in GitHub Desktop.
MPT1327/MPT1343 Check Byte calculation
// 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