DMR: Remove Condition where VLC and TLC without FID 0x10 did not calculate RAS MAC attachments; Misc Tweaks to dburst RAS Indicator; #359

DMR: Tweak FLCO to remove 0x23 as a Cap+ Private Call when it is only a RAS indicator on a normal Private Call; Clarify Comments;

DMR: Tweak RAS MD5 loading to allow for a correction against a flat value (if needed in future based on observation);

DMR: Misc Tweaks to Vertex Standard Key Loading; #316
This commit is contained in:
lwvmobile
2026-09-06 17:57:42 -04:00
parent fb3dc75c47
commit cd5f0f4a8e
7 changed files with 42 additions and 40 deletions

View File

@@ -1,4 +1,4 @@
Build Version: AW 2026-39-gc97400a
Build Version: AW 2026-41-gfb3dc75
MBElib Version: 1.3.4
CODEC2 Support Enabled
@@ -182,7 +182,7 @@ Advanced Decoder options:
-, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value)
-, Secure04
-u <string> Manually Enter and Enforce Vertex Standard 10 or 64 Char Hex Key
-u <string> Manually Enter Vertex Standard 10 or 64 Char Hex Key
-u 10:1234567891 or 64:AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD
-u 0:0 no KS application, but apply the inversion to the interleave (clear errors on 256)

View File

@@ -340,9 +340,8 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
/* R(0) to R(2) may be used to transport some
* Restricted Access System (RAS) information,
* So save these three bits after hamming correction
* See patent US 2013/0288643 A1 */
//TODO: Get seperate validity for line 0 and column 0,1,2
* See patent https://patents.google.com/patent/US20130288643A1
*/
if (HammingIrrecoverableErrorNb == 0)
{
R[0] = DataMatrix[0][2]; /* Save R(0) */

View File

@@ -410,50 +410,48 @@ void ras_effective_key_creation(dsd_state * state, char * input)
fprintf (stderr, "\n");
//The following rules are still not entirely clear, however,
//the first one executed (last byte) has been observed to be
//true, the SEED values are more speculative, values of
//0 and 0x1F do not change the 5-bit checksum mod 31 (0x1F)
//the last taken digest byte has been observed to be true
//Furthermore, it is still unclear how any rollover is handled,
//if adding 2 is byte inclusive (effectively resetting the byte)
//or if the value is flat 56-bit value and rollover occurs
//to the next value over, using best guess on this
//until further informatin comes along
//against the flat value, using best guess on this
//until further information comes along
//Below patent also suggest all bytes cannot equal zero
//and if so, the next portion of MD5 may be used,
//or some other method may be utilized to prevent fringe cases
//https://patents.google.com/patent/US20130288643A1
//Last Byte low5 not allowed to be 0x1F (reasons unclear, but observed true)
//Last Collected Byte 5-bit LSB not allowed to be 0x1F
if ((ctx.digest[6] & 0x1F) == 0x1F)
{
fprintf (stderr, " Byte %d: %02X -> %02X; ", 7, ctx.digest[6], ctx.digest[6]+2);
fprintf (stderr, " Byte %d: %02X -> %02X; ", 7, ctx.digest[6], (ctx.digest[6]+2) & 0xFF);
ctx.digest[6] += 2;
}
//UPDATE: I have now observed a system that has a 5-bit differential value of 0
//so that means that the low5 effective key value can be either 0, or 0x1F
//collect 7 bytes of the MD5 Hash to create the flat key value
unsigned long long int flat_key = 0;
for (int i = 0; i < 7; i++)
{
flat_key <<= 8;
flat_key |= ctx.digest[i];
}
// //SEED low5 non-zero value (no change to 5-bit EMB checksum mod 31)
// if ((ctx.digest[0] & 0x1F) == 0)
//May switch to this correction method instead if the
//observed rollover is on a flat value and not a byte value
// if ((flat_key & 0x1F) == 0x1F)
// {
// fprintf (stderr, " Byte %d: %02X -> %02X; ", 1, ctx.digest[0], ctx.digest[0]+2);
// ctx.digest[0] += 2;
// }
// //SEED low5 plus 1F (no change to 5-bit EMB checksum mod 31)
// else if ((ctx.digest[0] & 0x1F) == 0x1F)
// {
// fprintf (stderr, " Byte %d: %02X -> %02X; ", 1, ctx.digest[0], ctx.digest[0]+2);
// ctx.digest[0] += 2;
// fprintf (stderr, "Flat Correction: %014llX -> %014llX;\n", flat_key, flat_key+2);
// flat_key += 2;
// }
//byte-reverse the flat_key into the effective_key
unsigned long long int effective_key = 0;
for (int i = 0; i < 7; i++)
{
effective_key <<= 8;
effective_key |= ctx.digest[6-i];
effective_key |= (flat_key >> (i*8)) & 0xFF;
}
uint32_t ras_seed = effective_key & 0xFFFFFFFF;
@@ -467,5 +465,4 @@ void ras_effective_key_creation(dsd_state * state, char * input)
fprintf (stderr, "\n");
}

View File

@@ -271,11 +271,15 @@ void vertex_40_keystream_creation(dsd_state * state, unsigned long long int key_
vtx_key |= BPK[rc4_bytes[i]];
}
#ifdef VERTEX_KEY40_BY_TG
//skip constant verbosity on keyloading
#else
fprintf (stderr,"Vertex RC4 Bytes: ");
for (uint16_t i = 0; i < 8; i++)
fprintf (stderr, "%02X ", rc4_bytes[i]);
fprintf (stderr, "Vertex Keystream: %016llX;", (unsigned long long int)vtx_key);
fprintf (stderr, "\n");
#endif
uint8_t vtx_bytes[8];
memset (vtx_bytes, 0, sizeof(vtx_bytes));
@@ -316,12 +320,17 @@ void vertex_keystream_setup(dsd_state * state, char * input)
if (len == 10)
{
sscanf (curr, "%llx", &state->vtx40_key);
fprintf (stderr, "Vertex Standard 40-bit Key: %010llX \n", state->vtx40_key);
vertex_40_keystream_creation(state, state->vtx40_key);
}
else if (len == 64)
{
memcpy(state->vtx256_key, curr, 64);
fprintf (stderr, "Vertex Standard 256-bit Key: ");
for (int i = 0; i < 64; i++)
fprintf (stderr, "%c", state->vtx256_key[i]);
fprintf (stderr, "\n");
vertex_256_keystream_creation(state, curr);
}

View File

@@ -260,9 +260,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
if (IrrecoverableErrors == 0 && BPTCDmrDataByte[1] == 0x68) is_ras = 0;
//make sure if this is link control, the FID is set to 0x10
if (IrrecoverableErrors == 0 && is_lc && BPTCDmrDataByte[1] != 0x10) is_ras = 0;
//make sure if this is a PI header, the FID is set to 0x10
if (IrrecoverableErrors == 0 && databurst == 0x00 && BPTCDmrDataByte[1] != 0x10) is_ras = 0;
@@ -634,7 +631,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
}
//might flicker the terminal on partially enabled systems, may need to find a better placement
if (IrrecoverableErrors == 0 && (is_bptc || is_emb) && databurst != 0x05 && databurst != 0x07)
if (IrrecoverableErrors == 0 && (is_bptc || is_emb) && databurst != 0x05 && databurst != 0x07 && databurst != 0x09)
state->dmr_is_ras = is_ras;
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && is_ras == 0 && databurst != 0x09 && databurst != 0x05)

View File

@@ -512,15 +512,15 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
if (opts->payload == 1 && is_xpt == 1 && flco == 0x3) fprintf(stderr, "HASH=%d ", tg_hash);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
//0x07 on a VLC seems to indicate a Cap+ Private Call Header
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ or Cap+ TXI Private Call in progress (RAS)
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto (non-specific) Group Call in progress (RAS)
//its possible that both EMB FID 0x10 FLCO 0x20 and 0x23 are just Moto but non-specific (RAS)
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator <--need to find this again and re-evaluate
//0x04 on a VLC seems to indicate a Cap+ Group Call Header <--single bit flip from normal group
//0x07 on a VLC seems to indicate a Cap+ Private Call Header <--single bit flip from normal private
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto w/ FID 0x10 Group Call in progress (RAS)
//0x23 on the Embedded Voice Burst Sync seems to indicate a Moto w/ FID 0x10 Private Call in progress (RAS)
if (fid == 0x68) sprintf (state->call_string[slot], " Hytera ");
else if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
else if (flco == 0x4 || flco == 0x5 || flco == 0x7) //Cap+ Things (double check 0x05)
{
// sprintf (state->call_string[slot], " Cap+");
sprintf (state->call_string[slot], "%s","");
@@ -540,13 +540,13 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
state->gi[slot] = 1;
}
}
else if (flco == 0x3) //UU_V_Ch_Usr
else if (flco == 0x3 || flco == 0x23) //UU_V_Ch_Usr
{
sprintf (state->call_string[slot], " Private ");
fprintf (stderr, "Private ");
state->gi[slot] = 1;
}
else //Grp_V_Ch_Usr -- still valid on hytera VLC
else //Grp_V_Ch_Usr
{
sprintf (state->call_string[slot], " Group ");
fprintf (stderr, "Group ");

View File

@@ -1596,7 +1596,7 @@
printf (" -, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value) \n");
printf (" -, Secure04\n");
printf (" \n");
printf (" -u <string> Manually Enter and Enforce Vertex Standard 10 or 64 Char Hex Key \n");
printf (" -u <string> Manually Enter Vertex Standard 10 or 64 Char Hex Key \n");
printf (" -u 10:1234567891 or 64:AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD\n");
printf (" -u 0:0 no KS application, but apply the inversion to the interleave (clear errors on 256)\n");
printf (" \n");