DMR: Add 15-bit scrambler method for Kenwood Radios; #303

This commit is contained in:
lwvmobile
2025-08-17 18:57:32 -04:00
parent a5b9984d78
commit 8df8ce85f2
5 changed files with 82 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
Build Version: AW 2025-173-g21c02ac
Build Version: AW 2025-175-ga5b9984
MBElib Version: 1.3.4
CODEC2 Support Enabled
@@ -173,16 +173,18 @@ Advanced Decoder options:
-1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value)
-2 <hex> Manually Enter TYT and Enforce 16-bit BP Key Value (DMR) (Hex Value)
-2 <hex> Manually Enter and TYT Enforce 16-bit BP Key Value (DMR) (Hex Value)
-! <hex> Manually Enter TYT and Enforce Advanced Privacy (PC4) AP Hex Key (see example below)
-! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) AP Hex Key (see example below)
Encapulate in Single Quotation Marks; Space every 16 chars.
-! '736B9A9C5645288B 243AD5CB8701EF8A'
-5 <hex> Manually Enter TYT and Enforce Enhanced Privacy (AES-128) EP Hex Key (see example below)
-5 <hex> Manually Enter and Enforce TYT Enhanced Privacy (AES-128) EP Hex Key (see example below)
Encapulate in Single Quotation Marks; Space every 16 chars.
-5 '736B9A9C5645288B 243AD5CB8701EF8A'
-9 <dec> Manually Enter and Enforce Kenwood 15-bit Scrambler Key Value (DMR) (Dec Value)
-k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.
Only supports NXDN, DMR Basic Privacy (decimal value).
(dPMR and Hytera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!).

View File

@@ -992,6 +992,11 @@ typedef struct
int tyt_bp;
int tyt_ep;
//kenwood scrambler on DMR with forced application
int ken_sc;
uint8_t static_ks_bits[2][882];
int static_ks_counter[2];
} dsd_state;
/*

View File

@@ -56,6 +56,19 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
//Kenwood w/ Scrambler Application on DMR (disable this if clash with other link control, its obscure)
uint8_t is_kenwood_sc = 1;
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && pf == 1 && fid == 0x20 && (so & 0x40) == 0x40)
{
pf = 0; //turn off PF flag
fid = 0; //unclear if this signals FID (or is cipher type for scrambler)
//reset bit counter on static key bit counter (should do this after VC6 instead of relying on this, but meh, obscure cipher type)
state->static_ks_counter[state->currentslot] = 0;
is_kenwood_sc = 1;
}
//read ahead a little to get this for the xpt flag
if (*IrrecoverableErrors == 0 && flco == 0x09 && fid == 0x68)
{
@@ -295,7 +308,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
//unknown other manufacturer or OTA ENC, etc.
//removed tait from the list, added hytera 0x08
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08)
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08 && is_kenwood_sc == 0)
{
if (type == 1) fprintf (stderr, "%s \n", KYEL);
if (type == 2) fprintf (stderr, "%s \n", KYEL);
@@ -651,6 +664,9 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
state->gi[slot] = 1;
}
if (is_kenwood_sc)
fprintf(stderr, "Kenwood Scrambler ");
fprintf(stderr, "Call ");

View File

@@ -607,6 +607,9 @@
memset (state->s_ru, 0, sizeof(state->s_ru));
memset (state->s_l4u, 0, sizeof(state->s_l4u));
memset (state->s_r4u, 0, sizeof(state->s_r4u));
//we do reset the counter, but not the static_ks_bits
memset (state->static_ks_counter, 0, sizeof(state->static_ks_counter));
} //nocarrier
@@ -1086,6 +1089,8 @@
state->tyt_ap = 0;
state->tyt_bp = 0;
state->tyt_ep = 0;
state->ken_sc = 0;
//ks array storage and counters
memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
@@ -1095,6 +1100,9 @@
state->octet_counter = 0;
state->bit_counterL = 0;
state->bit_counterR = 0;
memset (state->static_ks_bits, 0, sizeof(state->static_ks_bits));
memset (state->static_ks_counter, 0, sizeof(state->static_ks_counter));
//AES Specific Variables
memset (state->aes_key, 0, sizeof(state->aes_key));
@@ -1579,16 +1587,18 @@
printf (" \n");
printf (" -1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n");
printf (" \n");
printf (" -2 <hex> Manually Enter TYT and Enforce 16-bit BP Key Value (DMR) (Hex Value) \n");
printf (" -2 <hex> Manually Enter and TYT Enforce 16-bit BP Key Value (DMR) (Hex Value) \n");
printf (" \n");
printf (" -! <hex> Manually Enter TYT and Enforce Advanced Privacy (PC4) AP Hex Key (see example below)\n");
printf (" -! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) AP Hex Key (see example below)\n");
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
printf (" -! '736B9A9C5645288B 243AD5CB8701EF8A' \n");
printf (" \n");
printf (" -5 <hex> Manually Enter TYT and Enforce Enhanced Privacy (AES-128) EP Hex Key (see example below)\n");
printf (" -5 <hex> Manually Enter and Enforce TYT Enhanced Privacy (AES-128) EP Hex Key (see example below)\n");
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
printf (" -5 '736B9A9C5645288B 243AD5CB8701EF8A' \n");
printf (" \n");
printf (" -9 <dec> Manually Enter and Enforce Kenwood 15-bit Scrambler Key Value (DMR) (Dec Value) \n");
printf (" \n");
printf (" -k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.\n");
printf (" Only supports NXDN, DMR Basic Privacy (decimal value). \n");
printf (" (dPMR and Hytera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!). \n");
@@ -1907,7 +1917,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:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF:!:01:2:345:6:7:89Ek: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:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF:!:01:2:345:6:7:89:Ek:I:J:O")) != -1)
{
switch (c)
@@ -1962,12 +1972,6 @@
fprintf (stderr, "TG Hold set to %d \n", state.tg_hold);
break;
case '9': //Leaving Enabled to maintain backwards compatability
state.ea_mode = 0;
state.esk_mask = 0;
fprintf (stderr,"Force Enabling EDACS Standard/Networked Mode Mode without ESK.\n");
break;
//experimental audio monitoring
case '8':
opts.monitor_input_audio = 1;
@@ -2054,9 +2058,35 @@
//load static keystream into ctx.bits since that isn't ever zeroed out
for (int i = 0; i < 49; i++)
ctx.bits[i] = ks_bits[i];
fprintf (stderr,"DMR TYT EP (AES-128) Key %016llX %016llX with Forced Application\n", K1, K2);
fprintf (stderr,"DMR TYT EP (AES-128) Key %016llX%016llX with Forced Application\n", K1, K2);
state.tyt_ep = 1;
break;
case '9':
/*
SLOT 1 Protected LC FLCO=0x00 FID=0x20 <--this link appears to indicate scrambler usage from Kenwood on DMR
DMR PDU Payload [80][20][40][00][00][01][00][00][01] SB: 00000000000 - 000;
SLOT 1 TGT=1 SRC=1 FLCO=0x00 FID=0x00 SVC=0x00 Group Call <--same call, but no scrambler on same Kenwood Radio
DMR PDU Payload [00][00][00][00][00][01][00][00][01]
For This, we could possible transition this to not be enforced
since we may have a positive indicator in link control,
but needs further samples and validation
*/
int lfsr = 0, bit = 0;
sscanf (optarg, "%ld", &lfsr);
fprintf (stderr,"DMR Kenwood 15-bit Scrambler Key %05d with Forced Application\n", lfsr);
for (int i = 0; i < 882; i++)
{
state.static_ks_bits[0][i] = lfsr & 0x1;
state.static_ks_bits[1][i] = lfsr & 0x1;
bit = ( (lfsr >> 1) ^ (lfsr >> 0) ) & 1;
lfsr = ( (lfsr >> 1 ) | (bit << 14) );
}
state.ken_sc = 1;
break;
case '3':
opts.dmr_le = 0;

View File

@@ -832,6 +832,13 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
ambe_d[i] ^= (uint8_t)(ctx.bits[i] & 1);
}
//DMR Kenwood Scrambler, Either Slot (static single key'd enforced KS) //should probably break this up, but this is a test for now
if (state->ken_sc == 1)
{
for (int i = 0; i < 49; i++)
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%882] & 1); //Yikes!
}
//P25p2 RC4 Handling, VCH 0
if (state->currentslot == 0 && state->payload_algid == 0xAA && state->R != 0 && ((state->synctype == 35) || (state->synctype == 36)))
{
@@ -1267,6 +1274,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
}
if (state->ken_sc == 1)
state->dmr_encL = 0;
//reverse mute testing, only mute unencrypted traffic (slave piggyback dsd+ method)
if (opts->reverse_mute == 1)
{
@@ -1344,6 +1354,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
}
if (state->ken_sc == 1)
state->dmr_encR = 0;
//reverse mute testing, only mute unencrypted traffic (slave piggyback dsd+ method)
if (opts->reverse_mute == 1)
{