MBE: Tweaks to DMRA Late Entry IV (change run order to align w/ superframe) for SDRTrunk .mbe files; #298

MBE: Fixes for non forced DMRA supported decryption modes (with supplied IV + expansion in mbe file, etc);

MBE: Support for DMRA DES Mode (rare and untested for .mbe files);
This commit is contained in:
lwvmobile
2026-07-20 23:02:17 -04:00
parent 272f17bfa3
commit 5e5c3c4555
3 changed files with 72 additions and 19 deletions

View File

@@ -1660,6 +1660,7 @@ unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
void hytera_enhanced_alg_refresh(dsd_state * state);
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES
void lfsr_32_to_128(uint8_t * iv);
void lfsr_64_to_128(uint8_t * iv);
void LFSR128(dsd_state * state);
void LFSR128n(dsd_state * state);

View File

@@ -374,6 +374,33 @@ void LFSR64(dsd_state * state)
}
}
//if supplied IV is only 32-bit in value, then expand it to a 128-bit IV using these LFSR taps (packed array)
void lfsr_32_to_128(uint8_t * iv)
{
uint64_t lfsr = 0, bit = 0;
lfsr = ((uint64_t)iv[0] << 24ULL) + ((uint64_t)iv[1] << 16ULL) + ((uint64_t)iv[2] << 8ULL) + ((uint64_t)iv[3] << 0ULL);
uint8_t cnt = 0, x = 32;
for(cnt = 0;cnt < 96; cnt++)
{
//32,22,2,1 (per Xilinx XAPP 052) Table 3: Taps for Maximum-Length LFSR Counters
bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
lfsr = (lfsr << 1) | bit;
//continue packing iv
iv[x/8] = (iv[x/8] << 1) + bit;
x++;
}
fprintf (stderr, "\n IV(128): ");
for (x = 0; x < 16; x++)
fprintf (stderr, "%02X", iv[x]);
fprintf (stderr, "\n");
}
//Expand a 32-bit MI into a 128-bit IV for AES
void LFSR128d(dsd_state * state)

View File

@@ -1027,7 +1027,7 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
//force slot to 0
state->currentslot = 0;
uint8_t c3_hex = (uint64_t)ConvertBitIntoBytes(c3, 4);
uint8_t c3_hex = (uint8_t)ConvertBitIntoBytes(c3, 4);
//debug
// fprintf (stderr, "\n AMBE#: %02d / %d / %d; F: %X;", ambe2_counter, ambe2_counter/3, ambe2_counter%3, c3_hex);
@@ -1035,17 +1035,6 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
//use div and mod 3 to set current storage fragment
state->late_entry_mi_fragment[0][(ambe2_counter/3)+1][ambe2_counter%3] = c3_hex;
//run LFSR evaluate stored codewords for matching IV or replace if not match or not set
if (ambe2_counter == 17)
{
if (state->forced_alg_id == 0x21 && state->payload_mi != 0)
{
fprintf (stderr, "\n");
LFSR(state);
}
fprintf (stderr, "\n");
dmr_late_entry_mi (opts, state);
}
}
char ambe_d[49]; memset(ambe_d, 0, sizeof(ambe_d));
@@ -1598,6 +1587,23 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
}
//Forced Application of DMRA DES Mode (untested on .mbe real samples)
if (alg_id == 0x22 && state->R != 0 && state->payload_mi != 0)
{
//expand IV from 32 to 64 (late entry iv should fix this)
// if (alg_id == 0x22)
// LFSR64(state);
uint8_t ks_bytes[375];
memset(ks_bytes, 0, sizeof(ks_bytes));
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
unpack_byte_array_into_bit_array(ks_bytes+8, ks, 256-8);
ks_available = 1;
}
}
//TODO: This
else if (state->forced_alg_id == 1) //Basic Privacy
@@ -1737,7 +1743,11 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
//debug set value
if (opts->payload == 1)
fprintf (stderr, "\n IV: %016llX;", iv_hex); //not really needed if loaded into array
{
if (iv_hex > 0xFFFFFFFF)
fprintf (stderr, "\n IV: %016llX;", iv_hex);
else fprintf (stderr, "\n IV: %08llX;", iv_hex);
}
//debug print current str_buffer
// fprintf (stderr, "\n Encryption MI/IV: %s", str_buffer);
@@ -1789,10 +1799,14 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
}
//P25 DES (v1 tested and working on P1, v2 should be okay now)
else if (alg_id == 0x81 && state->R != 0)
//P25 and DMR DES (v1 tested and working on P1, v2 should be okay now), DMR Untested but should be okay
else if ((alg_id == 0x22 || alg_id == 0x81) && state->R != 0)
{
//expand IV from 32 to 64
if (alg_id == 0x22)
LFSR64(state);
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
if (protocol == 1) //Phase 1 IMBE start on 19 for DES-OFB (8 discard + 9 LCW + 2 reserved)
@@ -1829,8 +1843,8 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
}
//P25 AES (v1 and v2 tested working on P1)
else if ( (alg_id == 0x84 || alg_id == 0x89) && state->aes_key_loaded[0] == 1 )
//P25 and DMR AES (v1 and v2 tested working on P1), working on DMR
else if ( (alg_id == 0x24 || alg_id == 0x25 || alg_id == 0x84 || alg_id == 0x89) && state->aes_key_loaded[0] == 1 )
{
uint8_t aes_key[32];
@@ -1858,9 +1872,11 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
aes_last_iv[i] = aes_iv[i];
//Resolve the longer IV from the shorter one
lfsr_64_to_128(aes_iv);
if (alg_id == 0x24 || alg_id == 0x25)
lfsr_32_to_128(aes_iv);
else lfsr_64_to_128(aes_iv);
if (alg_id == 0x89) //128, or 256
if (alg_id == 0x89 || alg_id == 0x24) //128, or 256
aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 0, 16); //16*16=256
else aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 2, 16); //16*16=256
@@ -2024,6 +2040,15 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
//reset if over for DMR 18 AMBE+2 frames
if (dmra_le && ambe2_counter == 18)
{
//run LFSR evaluate stored codewords for matching IV or replace if not match or not set
if (state->forced_alg_id == 0x21 && state->payload_mi != 0)
{
fprintf (stderr, "\n");
LFSR(state);
}
fprintf (stderr, "\n");
dmr_late_entry_mi (opts, state);
ambe2_counter = 0;
ks_idx = 0;
}