DMR: Add -M option to allow forcing any algid value;

Remove Setting from DMR_LE and place in MBE section instead;

Change state->M to state->forced_alg_id to make it easier to find later;
This commit is contained in:
lwvmobile
2025-10-31 09:41:10 -04:00
parent 14edf325bc
commit eb76ea2039
11 changed files with 68 additions and 62 deletions

View File

@@ -1,4 +1,4 @@
Build Version: AW 2025-207-gf8521fd
Build Version: AW 2025-209-g14edf32
MBElib Version: 1.3.4
CODEC2 Support Enabled
@@ -127,7 +127,7 @@ Advanced Decoder options:
Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal
-b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)
(NOTE: This used to be the 'K' option!
(NOTE: This used to be the 'K' option!)
-H <hex> Manually Enter Hytera 10/32/64 Char Basic Privacy Hex Key (see example below)
Encapulate in Single Quotation Marks; Space every 16 chars.
@@ -193,6 +193,8 @@ Advanced Decoder options:
-0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)
-M <hex> Force Entered Alg ID Value over Missing PI header/LE Encryption Identifiers (DMR)
-3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst)
Note: Disable this if false positives on Voice ENC occur.

View File

@@ -632,7 +632,7 @@ typedef struct
unsigned long long int K2;
unsigned long long int K3;
unsigned long long int K4;
int M;
uint8_t forced_alg_id;
int menuopen;
//AES Key Segments

View File

@@ -14,23 +14,6 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
uint8_t slot = state->currentslot;
//enforce RC4 due to missing PI header, but with valid SVC Opts
//ideally, this would be handled by VC-F single burst, but its not fully reliable compared to this
//due to multiple signalling occurring inside of it, depending on system type
if (state->M == 0x21)
{
if (slot == 0 && state->dmr_so & 0x40)
{
state->payload_algid = 0x21;
state->payload_keyid = 0xFF;
}
if (slot == 1 && state->dmr_soR & 0x40)
{
state->payload_algidR = 0x21;
state->payload_keyidR = 0xFF;
}
}
//collect our fragments and place them into storage
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4);
@@ -535,7 +518,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
if (state->dmr_so & 0x40 && key != 0 && alg != 0)
{
//if we aren't forcing a particular alg or privacy key set
if (state->M == 0)
if (state->forced_alg_id == 0)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);
@@ -561,7 +544,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
if (state->dmr_soR & 0x40 && key != 0 && alg != 0)
{
//if we aren't forcing a particular alg or privacy key set
if (state->M == 0)
if (state->forced_alg_id == 0)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);

View File

@@ -1034,7 +1034,7 @@
state->K2 = 0;
state->K3 = 0;
state->K4 = 0;
state->M = 0; //force key priority over settings from fid/so
state->forced_alg_id = 0; //force key priority over settings from fid/so
state->dmr_stereo = 0; //1, or 0?
state->dmrburstL = 17; //initialize at higher value than possible
@@ -1514,7 +1514,7 @@
printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n");
printf ("\n");
printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
printf (" (NOTE: This used to be the 'K' option! \n");
printf (" (NOTE: This used to be the 'K' option!) \n");
printf ("\n");
printf (" -H <hex> Manually Enter Hytera 10/32/64 Char Basic Privacy Hex Key (see example below)\n");
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
@@ -1580,6 +1580,8 @@
printf (" \n");
printf (" -0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR) \n");
printf (" \n");
printf (" -M <hex> Force Entered Alg ID Value over Missing PI header/LE Encryption Identifiers (DMR) \n");
printf (" \n");
printf (" -3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
printf (" Note: Disable this if false positives on Voice ENC occur. \n");
printf ("\n");
@@ -1884,7 +1886,7 @@
exitflag = 0;
while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF@:!:01:2:345:6:^:7:8_:9:Ek:I:J:O+:")) != -1)
while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:G:D:L:V:U:YK:b:H:X:M:NQ:WrlZTF@:!:01:2:345:6:^:7:8_:9:Ek:I:J:O+:")) != -1)
{
switch (c)
@@ -1934,9 +1936,14 @@
//rc4 enforcement on DMR (due to missing the PI header)
case '0':
state.M = 0x21;
state.forced_alg_id = 0x21;
fprintf (stderr,"Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)\n");
break;
case 'M':
sscanf (optarg, "%hhX", &state.forced_alg_id);
fprintf (stderr,"Force DMR ALG ID 0x%02X over Missing PI header/LE Encryption Identifiers (DMR)\n", state.forced_alg_id);
break;
//load single rc4/des key
case '1':
@@ -2234,7 +2241,7 @@
break;
case '4':
state.M = 1;
state.forced_alg_id = 1;
fprintf (stderr,"Force Privacy Key over Encryption Identifiers (DMR BP and NXDN Scrambler) \n");
break;

View File

@@ -185,6 +185,20 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
char zeroes[49]; memset(zeroes, 0, sizeof(zeroes));
size_t zeroes_threshold = 20;
if (state->forced_alg_id > 1 && state->forced_alg_id != 0x16) //1 and 0x16 is saved for BP stuff, so anything higher than that (Kirisun, requires svc opts set as well)
{
if (state->currentslot == 0 && state->dmr_so & 0x40)
{
state->payload_algid = state->forced_alg_id;
state->payload_keyid = 0xFF;
}
if (state->currentslot == 1 && state->dmr_soR & 0x40)
{
state->payload_algidR = state->forced_alg_id;
state->payload_keyidR = 0xFF;
}
}
//these conditions should ensure no clashing with the BP/HBP/Scrambler key loading machanisms already coded in
if (state->currentslot == 0 && state->payload_algid != 0 && state->payload_algid != 0x80 && state->keyloader == 1)
keyring (opts, state);
@@ -460,7 +474,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
if ( (state->nxdn_cipher_type == 0x01 && state->R != 0) ||
(state->M == 1 && state->R > 0) )
(state->forced_alg_id == 1 && state->R > 0) )
{
if (state->payload_miN == 0)
@@ -568,7 +582,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//EXPERIMENTAL!!
//load basic privacy key number from array by the tg value (if not forced)
//currently only Moto BP and Hytera 10 Char BP
if (state->M == 0 && state->payload_algid == 0)
if (state->forced_alg_id == 0 && state->payload_algid == 0)
{
//see if we need to hash a value larger than 16-bits
hash = state->lasttg & 0xFFFFFF;
@@ -594,7 +608,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
(state->K > 0 && state->M == 1) )
(state->K > 0 && state->forced_alg_id == 1) )
{
k = BPK[state->K];
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
@@ -606,7 +620,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
(state->K1 > 0 && state->M == 1) )
(state->K1 > 0 && state->forced_alg_id == 1) )
{
int pos = 0;
@@ -1030,7 +1044,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//EXPERIMENTAL!!
//load basic privacy key number from array by the tg value (if not forced)
//currently only Moto BP and Hytera 10 Char BP
if (state->M == 0 && state->payload_algidR == 0)
if (state->forced_alg_id == 0 && state->payload_algidR == 0)
{
//see if we need to hash a value larger than 16-bits
hash = state->lasttgR & 0xFFFFFF;
@@ -1056,7 +1070,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
if ( (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ||
(state->K > 0 && state->M == 1) )
(state->K > 0 && state->forced_alg_id == 1) )
{
k = BPK[state->K];
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
@@ -1068,7 +1082,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
if ( (state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ||
(state->K1 > 0 && state->M == 1))
(state->K1 > 0 && state->forced_alg_id == 1))
{
int pos = 0;

View File

@@ -211,14 +211,14 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr)
{
if (state->M == 1 || state->M == 0x21) state->M = 0;
else state->M = 1;
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
else state->forced_alg_id = 1;
}
if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry
{
if (state->M == 1 || state->M == 0x21) state->M = 0;
else state->M = 0x21;
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
else state->forced_alg_id = 0x21;
}
if (c == 105) //'i' key, toggle signal inversion on inverted types

View File

@@ -921,11 +921,11 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
//toggle enforcement of basic privacy key over enc bit set on traffic
if (option == 4)
{
if (state->M == 1 || state->M == 0x21)
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21)
{
state->M = 0;
state->forced_alg_id = 0;
}
else state->M = 1;
else state->forced_alg_id = 1;
}
if (option == 5)
@@ -951,11 +951,11 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
//toggle enforcement of rc4 key over missing pi header/le on DMR
// if (option == 6)
// {
// if (state->M == 1 || state->M == 0x21)
// if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21)
// {
// state->M = 0;
// state->forced_alg_id = 0;
// }
// else state->M = 0x21;
// else state->forced_alg_id = 0x21;
// }
//load AES keys

View File

@@ -495,18 +495,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
#endif
// if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
if (state->M == 1)
if (state->forced_alg_id == 1)
{
if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R);
if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K);
if (state->K1 != 0) printw ("| Forcing Key Priority -- Hytera BP Key: %016llX \n", state->K1);
if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required
}
if (state->M == 0x21)
if (state->forced_alg_id == 0x21)
{
if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R);
}
if (state->M == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
if (state->forced_alg_id == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
if (opts->scanner_mode == 1)
{

View File

@@ -303,7 +303,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
fprintf (stderr, "PF 1/1");
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
@@ -361,7 +361,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
if (part_of_frame == 0)
{
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
}
// if (crc != check)
@@ -378,13 +378,13 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1)
{
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
}
//this seems to work much better now
else if (part_of_frame != 0 && state->nxdn_cipher_type == 0x1)
{
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
//advance seed by required number of turns depending on the current pf value
int start = 0; int end = part_of_frame;
@@ -587,7 +587,7 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
memcpy(state->dmr_pdu_sf[0]+sf_idx, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
//if force application of scrambler key, then let's reset, regardless of CRC check
if (sf_fb && state->M == 1)
if (sf_fb && state->forced_alg_id == 1)
state->payload_miN = 0;
//currently using static values so event log will log something, and do wav files, etc
@@ -1323,7 +1323,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1)
{
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
}
/*

View File

@@ -189,7 +189,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
state->nxdn_last_rid = 0;
state->nxdn_last_tg = 0;
if (state->M == 0)
if (state->forced_alg_id == 0)
state->nxdn_cipher_type = 0;
sprintf (state->nxdn_call_type, "%s", "");
@@ -207,7 +207,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
state->nxdn_last_rid = 0;
state->nxdn_last_tg = 0;
if (state->M == 0)
if (state->forced_alg_id == 0)
state->nxdn_cipher_type = 0;
sprintf (state->nxdn_call_type, "%s", "");
#endif
@@ -689,7 +689,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
state->payload_miN = state->R; //should be okay to load here, will test
}
if (state->M == 1) state->nxdn_cipher_type = 0x1;
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
}
//rtl
else if (opts->audio_in_type == 3)
@@ -737,7 +737,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
state->payload_miN = state->R; //should be okay to load here, will test
}
if (state->M == 1) state->nxdn_cipher_type = 0x1;
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
#endif
}
@@ -1760,7 +1760,7 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
//check the rkey array for a scrambler key value
//TGT ID and Key ID could clash though if csv or system has both with different keys
if (state->rkey_array[id] != 0) state->R = state->rkey_array[id];
if (state->M == 1) state->nxdn_cipher_type = 0x1;
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
}
//rtl
else if (opts->audio_in_type == 3)
@@ -1779,7 +1779,7 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
//check the rkey array for a scrambler key value
//TGT ID and Key ID could clash though if csv or system has both with different keys
if (state->rkey_array[id] != 0) state->R = state->rkey_array[id];
if (state->M == 1) state->nxdn_cipher_type = 0x1;
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
#endif
}

View File

@@ -465,7 +465,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if (state->rkey_array[limazulu] != 0)
state->R = state->rkey_array[limazulu];
if (state->R != 0 && state->M == 1) state->nxdn_cipher_type = 0x1;
if (state->R != 0 && state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
//add additional time to last_sync_time for LimaZulu to hold on current frequency
//a little longer without affecting normal scan time on trunk_hangtime variable
@@ -521,7 +521,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if (voice && facch == 1) //facch steal 1 -- before voice
{
//force scrambler here, but with unspecified key (just use what's loaded)
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
if (state->forced_alg_id == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
{
@@ -580,7 +580,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
//update last voice sync time
state->last_vc_sync_time = time(NULL);
//turn on scrambler if forced by user option
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
if (state->forced_alg_id == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
//process voice frame
nxdn_voice (opts, state, voice, dbuf);
}