DMR: Hytera Over the Air Encryption (Signalling Encryption) Support; #373

DMR: Fix Hytera PDU Decryption to operate at Block Level; (Fixes confirmed data); #372

DMR: Hytera Enhanced RC4 allows variable len output for OTA, PDU or Voice;

DMR: Fix Segfault in RS12,9 encoder function where freeing static memory caused a crash;

Misc Code tweaks to accomodate new features;
This commit is contained in:
lwvmobile
2026-11-06 21:22:38 -05:00
parent 587181f4de
commit bfa4891965
15 changed files with 1825 additions and 261 deletions

View File

@@ -152,6 +152,10 @@ Advanced Decoder options:
-H C:128:736B9A9C5645288B243AD5CB8701EF8A' -H C:128:736B9A9C5645288B243AD5CB8701EF8A'
-H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8' -H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8'
-H <hex> Manually Enter Hytera OTA Encryption 32 Char Hex Key (see example below)
-H O:0:0 no keystream application, but check for Hytera OTA Encryption and DMRA EP Late Entry IV.
-H O:128:17bfe59b29a06136fb7d3811fd1a4904 for 128-bit RC4 OTA Key Setup
-R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value) -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)
-1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) -1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value)

View File

@@ -935,6 +935,20 @@ typedef struct
int ras_permutation_order[104]; int ras_permutation_order[104];
uint8_t dmr_is_ras; //indicate a partial or complete RAS enabled system uint8_t dmr_is_ras; //indicate a partial or complete RAS enabled system
//Hytera OTA Key Variables
// #define DEBUG_HOTA
uint8_t hota_enc_check;
uint8_t hota_key_loaded;
uint8_t dmr_is_hota;
int hota_bit_shift;
int hota_byte_shifts[12];
uint8_t hota_rc4_key[16];
uint8_t hota_rc4_ks[80];
uint8_t hota_lc_ctx[2][4];
uint8_t hota_ctx_ok[2];
int hota_sbrc_idx1[2];
int hota_sbrc_idx2[2];
//Bitmap Filtering Options //Bitmap Filtering Options
int audio_smoothing; int audio_smoothing;
@@ -1378,6 +1392,7 @@ void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output);
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3], uint8_t * is_ras); uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3], uint8_t * is_ras);
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]); uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]);
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd); uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd);
uint32_t BPTC_128x77_Check_Errors(uint8_t InputDataMatrix[8][16]);
//Reed Solomon DMR functions //Reed Solomon DMR functions
void rs_16_13_encode(uint8_t * input); void rs_16_13_encode(uint8_t * input);
@@ -1516,6 +1531,11 @@ void LFSRP(dsd_state * state);
void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state); void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state);
void LFSR64(dsd_state * state); void LFSR64(dsd_state * state);
//IV Reversals using LFSR tap +1 arrangements
uint64_t reverse_lfsr_32a_to_len(uint8_t * iv, int16_t len);
uint64_t reverse_lfsr_32d_to_len(uint8_t * iv, int16_t len);
uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len);
void Hamming_7_4_init(); void Hamming_7_4_init();
void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits); void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Hamming_7_4_decode(unsigned char *rxBits); bool Hamming_7_4_decode(unsigned char *rxBits);
@@ -1680,7 +1700,7 @@ uint32_t kirisun_lfsr(unsigned long long int mi);
void kirisun_keystream_creation(dsd_state * state); void kirisun_keystream_creation(dsd_state * state);
//Hytera Enhanced //Hytera Enhanced
void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value); void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value, int len);
unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len); unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
void hytera_enhanced_alg_refresh(dsd_state * state); void hytera_enhanced_alg_refresh(dsd_state * state);
@@ -1689,6 +1709,20 @@ uint32_t ras_mac_calculator(dsd_state * state, uint8_t * input, int input_len, i
void ras_effective_key_creation(dsd_state * state, char * input); void ras_effective_key_creation(dsd_state * state, char * input);
void ras_permute_order(uint32_t seed, int * order); void ras_permute_order(uint32_t seed, int * order);
//Hytera OTA Encryption
void hytera_ota_keystream_setup(dsd_state * state, char * input);
void hytera_ota_decrypt_bptc_96(dsd_state * state, uint8_t * input, uint8_t type);
void hytera_ota_decrypt_emb_lc(dsd_state * state, uint8_t input[8][16]);
void hytera_ota_search_emb_lc(dsd_state * state, uint8_t input[8][16]);
void hytera_ota_decrypt_sb_rc(dsd_state * state, uint8_t * input);
void hytera_ota_search_sb_rc(dsd_state * state, uint8_t * input, int ptype);
void hytera_create_lc_ctx(dsd_state * state, uint8_t * input);
void hytera_ota_unit_testing(dsd_state * state);
//Hytera Decryption for Data Blocks
uint8_t hytera_bp_data_decrypt(dsd_state * state, uint8_t * input, int len);
uint8_t hytera_ep_data_decrypt(dsd_opts * opts, dsd_state * state, uint8_t * input, int len);
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES //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_32_to_128(uint8_t * iv);
void lfsr_64_to_128(uint8_t * iv); void lfsr_64_to_128(uint8_t * iv);

View File

@@ -167,197 +167,283 @@ void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output)
/* /*
* @brief : This function extract the 96 bits of a deinteleaved 196 bits * BPTC (196,96) extract — ETSI TS 102 361-1 B.1.1
* buffer using BPTC (196,96) * Two-pass row Hamming(15,11) + column Hamming(13,9).
* * Debug: define BPTC_196x96_DEBUG 1 for row/col correction chatter.
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (196 bytes)
*
* @param DMRDataExtracted : Pointer where the DMR data will be written (96 bytes)
*
* @return The total number of irrecoverable Hamming check errors
*/ */
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3], uint8_t * is_ras)
// #define BPTC_196x96_DEBUG 1
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196],
uint8_t DMRDataExtracted[96],
uint8_t R[3],
uint8_t * is_ras)
{ {
uint32_t i, j, k; uint32_t i, j, k;
uint8_t DataMatrix[13][15]; uint8_t DataMatrix[13][15];
uint8_t LineUncorrected[15]; uint8_t LineUncorrected[15];
uint8_t LineBefore[15];
uint8_t LineCorrected[11]; uint8_t LineCorrected[11];
uint8_t ColumnUncorrected[13]; uint8_t ColumnUncorrected[13];
uint8_t ColumnBefore[13];
uint8_t ColumnCorrected[9]; uint8_t ColumnCorrected[9];
uint32_t HammingIrrecoverableErrorNb = 0; uint32_t HammingIrrecoverableErrorNb = 0;
uint32_t row_corr_p1 = 0, col_corr_p1 = 0;
uint32_t row_fail_p1 = 0, col_fail_p1 = 0;
uint32_t row_corr_p2 = 0, col_corr_p2 = 0;
uint32_t row_fail_p2 = 0, col_fail_p2 = 0;
/* First step : Reconstitute the BPTC 15x11 matrix UNUSED(row_corr_p1); UNUSED(col_corr_p1);
* Note : Input data shall be deinterleaved */ UNUSED(row_fail_p1); UNUSED(col_fail_p1);
k = 1; /* Discard R(3) bit - See DMR standard chapter B1.1 BPTC (196,96) */ UNUSED(row_corr_p2); UNUSED(col_corr_p2);
for(i = 0; i < 13; i++) UNUSED(row_fail_p2); UNUSED(col_fail_p2);
#if BPTC_196x96_DEBUG
fprintf (stderr, "\n");
#endif
/* Rebuild 13×15 matrix; discard R(3) at index 0 — DMR B.1.1 */
k = 1;
for (i = 0; i < 13; i++)
{ {
for(j = 0; j < 15; j++) for (j = 0; j < 15; j++)
{ {
/* Only the LSBit of the byte is stored */
DataMatrix[i][j] = (InputDeInteleavedData[k] & 1); DataMatrix[i][j] = (InputDeInteleavedData[k] & 1);
k++; k++;
} }
} }
/* Process the the Hamming (15,11,3) code /* ========== Pass 1: row Hamming(15,11) on rows 0..8 ========== */
* check on each line (first time). for (i = 0; i < 9; i++)
* Do not check the 4th last lines */
for(i = 0; i < 9; i++)
{ {
/* Get a full line */ for (j = 0; j < 15; j++)
for(j = 0; j < 15; j++)
{ {
LineUncorrected[j] = DataMatrix[i][j]; LineUncorrected[j] = DataMatrix[i][j];
LineBefore[j] = LineUncorrected[j];
} }
/* Apply Hamming (15,11,3) code correction */ if (Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
{ {
HammingIrrecoverableErrorNb++; HammingIrrecoverableErrorNb++;
row_fail_p1++;
#if BPTC_196x96_DEBUG
fprintf(stderr, " BPTC196 P1 ROW FAIL row=%u rx=", (unsigned)i);
for (j = 0; j < 15; j++)
fprintf(stderr, "%u", LineBefore[j] & 1);
fprintf(stderr, "\n");
#endif
/* Keep original data bits on failure */
for (j = 0; j < 11; j++)
DataMatrix[i][j] = LineBefore[j];
} }
else
/* Re-inject the line in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 11; j++)
{ {
DataMatrix[i][j] = LineCorrected[j]; /* rxBits were corrected in place; note any flip */
for (j = 0; j < 15; j++)
{
if ((LineBefore[j] & 1) != (LineUncorrected[j] & 1))
{
row_corr_p1++;
#if BPTC_196x96_DEBUG
fprintf(stderr,
" BPTC196 P1 ROW CORRECTED row=%u bit=%u %u->%u\n",
(unsigned)i, (unsigned)j,
(unsigned)(LineBefore[j] & 1),
(unsigned)(LineUncorrected[j] & 1));
#endif
}
}
for (j = 0; j < 11; j++)
DataMatrix[i][j] = LineCorrected[j];
} }
} }
#if BPTC_196x96_DEBUG
if (row_fail_p1 || row_corr_p1)
fprintf(stderr, " BPTC196 P1 ROW summary: fail=%u corrected_bits=%u\n",
(unsigned)row_fail_p1, (unsigned)row_corr_p1);
#endif
/* ========== Pass 1: column Hamming(13,9) on cols 0..14 ========== */
/* Process the the Hamming (15,11,3) code for (i = 0; i < 15; i++)
* check on each column/row (first time) */
for(i = 0; i < 15; i++)
{ {
/* Get a full column */ for (j = 0; j < 13; j++)
for(j = 0; j < 13; j++)
{ {
ColumnUncorrected[j] = DataMatrix[j][i]; ColumnUncorrected[j] = DataMatrix[j][i];
ColumnBefore[j] = ColumnUncorrected[j];
} }
/* Apply Hamming (15,11,3) code correction */ if (Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
{ {
HammingIrrecoverableErrorNb++; HammingIrrecoverableErrorNb++;
col_fail_p1++;
#if BPTC_196x96_DEBUG
fprintf(stderr, " BPTC196 P1 COL FAIL col=%u rx=", (unsigned)i);
for (j = 0; j < 13; j++)
fprintf(stderr, "%u", ColumnBefore[j] & 1);
fprintf(stderr, "\n");
#endif
for (j = 0; j < 9; j++)
DataMatrix[j][i] = ColumnBefore[j];
} }
else
/* Re-inject the column in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 9; j++)
{ {
DataMatrix[j][i] = ColumnCorrected[j]; for (j = 0; j < 13; j++)
{
if ((ColumnBefore[j] & 1) != (ColumnUncorrected[j] & 1))
{
col_corr_p1++;
#if BPTC_196x96_DEBUG
fprintf(stderr,
" BPTC196 P1 COL CORRECTED col=%u bit=%u %u->%u\n",
(unsigned)i, (unsigned)j,
(unsigned)(ColumnBefore[j] & 1),
(unsigned)(ColumnUncorrected[j] & 1));
#endif
}
}
for (j = 0; j < 9; j++)
DataMatrix[j][i] = ColumnCorrected[j];
} }
} }
#if BPTC_196x96_DEBUG
if (col_fail_p1 || col_corr_p1)
fprintf(stderr, " BPTC196 P1 COL summary: fail=%u corrected_bits=%u\n",
(unsigned)col_fail_p1, (unsigned)col_corr_p1);
#endif
/* The first Hamming code check has maybe corrected bit /* Second pass can fix more after the first cascade */
* which can be use to correct other bit, so make the
* same operation twice */
/* Reset the number of irrecoverable errors */
HammingIrrecoverableErrorNb = 0; HammingIrrecoverableErrorNb = 0;
/* ========== Pass 2: rows ========== */
/* Process the the Hamming (15,11,3) code for (i = 0; i < 9; i++)
* check on each line (second time).
* Do not check the 4th last lines */
for(i = 0; i < 9; i++)
{ {
/* Get a full line */ for (j = 0; j < 15; j++)
for(j = 0; j < 15; j++)
{ {
LineUncorrected[j] = DataMatrix[i][j]; LineUncorrected[j] = DataMatrix[i][j];
LineBefore[j] = LineUncorrected[j];
} }
/* Apply Hamming (15,11,3) code correction */ if (Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
{ {
/* Row/Line contains irrecoverable errors */
HammingIrrecoverableErrorNb++; HammingIrrecoverableErrorNb++;
row_fail_p2++;
#if BPTC_196x96_DEBUG
fprintf(stderr, " BPTC196 P2 ROW FAIL row=%u rx=", (unsigned)i);
for (j = 0; j < 15; j++)
fprintf(stderr, "%u", LineBefore[j] & 1);
fprintf(stderr, "\n");
#endif
for (j = 0; j < 11; j++)
DataMatrix[i][j] = LineBefore[j];
} }
else else
{ {
/* Row/Line contains correct data */ for (j = 0; j < 15; j++)
} {
if ((LineBefore[j] & 1) != (LineUncorrected[j] & 1))
/* Re-inject the line in the matrix (only the util data [11 bit], {
* not the Hamming part [4 bit]) */ row_corr_p2++;
for(j = 0; j < 11; j++) #if BPTC_196x96_DEBUG
{ fprintf(stderr,
DataMatrix[i][j] = LineCorrected[j]; " BPTC196 P2 ROW CORRECTED row=%u bit=%u %u->%u\n",
(unsigned)i, (unsigned)j,
(unsigned)(LineBefore[j] & 1),
(unsigned)(LineUncorrected[j] & 1));
#endif
}
}
for (j = 0; j < 11; j++)
DataMatrix[i][j] = LineCorrected[j];
} }
} }
#if BPTC_196x96_DEBUG
if (row_fail_p2 || row_corr_p2)
fprintf(stderr, " BPTC196 P2 ROW summary: fail=%u corrected_bits=%u\n",
(unsigned)row_fail_p2, (unsigned)row_corr_p2);
#endif
/* ========== Pass 2: columns ========== */
/* Process the the Hamming (15,11,3) code for (i = 0; i < 15; i++)
* check on each column/row (second time) */
for(i = 0; i < 15; i++)
{ {
/* Get a full column */ for (j = 0; j < 13; j++)
for(j = 0; j < 13; j++)
{ {
ColumnUncorrected[j] = DataMatrix[j][i]; ColumnUncorrected[j] = DataMatrix[j][i];
ColumnBefore[j] = ColumnUncorrected[j];
} }
/* Apply Hamming (15,11,3) code correction */ if (Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
{ {
/* Row/Line contains irrecoverable errors */
HammingIrrecoverableErrorNb++; HammingIrrecoverableErrorNb++;
col_fail_p2++;
#if BPTC_196x96_DEBUG
fprintf(stderr, " BPTC196 P2 COL FAIL col=%u rx=", (unsigned)i);
for (j = 0; j < 13; j++)
fprintf(stderr, "%u", ColumnBefore[j] & 1);
fprintf(stderr, "\n");
#endif
for (j = 0; j < 9; j++)
DataMatrix[j][i] = ColumnBefore[j];
} }
else else
{ {
/* Row/Line contains correct data */ for (j = 0; j < 13; j++)
} {
if ((ColumnBefore[j] & 1) != (ColumnUncorrected[j] & 1))
/* Re-inject the column in the matrix (only the util data [11 bit], {
* not the Hamming part [4 bit]) */ col_corr_p2++;
for(j = 0; j < 9; j++) #if BPTC_196x96_DEBUG
{ fprintf(stderr,
DataMatrix[j][i] = ColumnCorrected[j]; " BPTC196 P2 COL CORRECTED col=%u bit=%u %u->%u\n",
(unsigned)i, (unsigned)j,
(unsigned)(ColumnBefore[j] & 1),
(unsigned)(ColumnUncorrected[j] & 1));
#endif
}
}
for (j = 0; j < 9; j++)
DataMatrix[j][i] = ColumnCorrected[j];
} }
} }
#if BPTC_196x96_DEBUG
if (col_fail_p2 || col_corr_p2)
fprintf(stderr, " BPTC196 P2 COL summary: fail=%u corrected_bits=%u\n",
(unsigned)col_fail_p2, (unsigned)col_corr_p2);
fprintf(stderr,
" BPTC196 FINAL irrecoverable=%u P1(row_f=%u col_f=%u row_c=%u col_c=%u) "
"P2(row_f=%u col_f=%u row_c=%u col_c=%u)\n",
(unsigned)HammingIrrecoverableErrorNb,
(unsigned)row_fail_p1, (unsigned)col_fail_p1,
(unsigned)row_corr_p1, (unsigned)col_corr_p1,
(unsigned)row_fail_p2, (unsigned)col_fail_p2,
(unsigned)row_corr_p2, (unsigned)col_corr_p2);
#endif
/* Extract the DMR data (96 bit) from the matrix */ /* Extract 96 data bits */
/* First line : Do not take R(2), R(1) and R(0) */
k = 0; k = 0;
for (i = 3; i < 11; i++)
for(i = 3; i < 11; i++)
{ {
DMRDataExtracted[k] = DataMatrix[0][i]; DMRDataExtracted[k++] = DataMatrix[0][i];
k++; }
for (i = 1; i < 9; i++)
{
for (j = 0; j < 11; j++)
DMRDataExtracted[k++] = DataMatrix[i][j];
} }
/* Next lines */
for(i = 1; i < 9; i++)
{
for(j = 0; j < 11; j++)
{
DMRDataExtracted[k] = DataMatrix[i][j];
k++;
}
}
/* 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 https://patents.google.com/patent/US20130288643A1
*/
if (HammingIrrecoverableErrorNb == 0) if (HammingIrrecoverableErrorNb == 0)
{ {
R[0] = DataMatrix[0][2]; /* Save R(0) */ R[0] = DataMatrix[0][2]; /* R(0) */
R[1] = DataMatrix[0][1]; /* Save R(1) */ R[1] = DataMatrix[0][1]; /* R(1) */
R[2] = DataMatrix[0][0]; /* Save R(2) */ R[2] = DataMatrix[0][0]; /* R(2) */
} }
if (R[0] == 0 && R[1] == 0 && R[2] == 1)
{
*is_ras = 1;
}
else *is_ras = 0;
/* Return the number of irrecoverable Hamming errors */ if (R[0] == 0 && R[1] == 0 && R[2] == 1)
*is_ras = 1;
else
*is_ras = 0;
return HammingIrrecoverableErrorNb; return HammingIrrecoverableErrorNb;
} /* End BPTC_196x96_Extract_Data() */ }
/* /*
@@ -383,6 +469,10 @@ uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDat
uint8_t row_bad[7]; uint8_t row_bad[7];
uint8_t col_bad[16]; uint8_t col_bad[16];
#if BPTC_128x77_DEBUG
fprintf (stderr, "\n");
#endif
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
{ {
for (j = 0; j < 16; j++) for (j = 0; j < 16; j++)
@@ -650,6 +740,52 @@ uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDat
} /* End BPTC_16x2_Extract_Data() */ } /* End BPTC_16x2_Extract_Data() */
uint32_t BPTC_128x77_Check_Errors(uint8_t InputDataMatrix[8][16])
{
uint32_t i, j;
uint32_t ham_bad = 0, ham_fix = 0, par_err = 0;
uint8_t line[16], before[16], decoded[11];
uint32_t ones;
int changed;
for (i = 0; i < 7; i++)
{
for (j = 0; j < 16; j++)
{
before[j] = (InputDataMatrix[i][j] & 1);
line[j] = before[j];
}
if (Hamming_16_11_4_decode(line, decoded, 1) == false)
{
ham_bad++;
}
else
{
changed = 0;
for (j = 0; j < 16; j++)
{
if (line[j] != before[j])
{
changed = 1;
break;
}
}
if (changed)
ham_fix++;
}
}
for (i = 0; i < 16; i++)
{
ones = 0;
for (j = 0; j < 7; j++)
ones += (InputDataMatrix[j][i] & 1);
if ((ones % 2) != (InputDataMatrix[7][i] & 1))
par_err++;
}
return ham_bad + ham_fix + par_err;
}
/* End of file */ /* End of file */

View File

@@ -530,7 +530,7 @@ void vertex_256_keystream_creation(dsd_state * state, char * key_string)
uint64_t vtx_key = 0; uint64_t vtx_key = 0;
//use the bytes from rc4 output to select 4 BP key 16-bit words //use the bytes from round key output to select 4 BP key 16-bit words
for (int i = 224; i < 228; i++) for (int i = 224; i < 228; i++)
{ {
vtx_key <<= 16; vtx_key <<= 16;

File diff suppressed because it is too large Load Diff

View File

@@ -1157,135 +1157,16 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
decrypted_pdu = 1; decrypted_pdu = 1;
} }
else if (alg == 0x68 && akl == 1) //Hytera BP else if (alg == 0x68) //Hytera BP
{ {
//just passing through to see if a key was loaded and the blocks decrypted
//Find len on loaded Hytera BP key w/ memcmp on kaes and load into ob decrypted_pdu = hytera_bp_data_decrypt(state, empt, 1);
int klen = 32;
uint8_t emp8[8];
memset(emp8, 0, sizeof(emp8));
//TODO: We are assumming the key isn't something like 0x100000000000000000000000000000.... zero fill to 16 or 32
//need to fix this checkdown, but may not be plausible without redoing the Hytera BP code entirely at this point
//test for 64 char (32 byte) key
if ((memcmp(emp8, kaes+16, 8) != 0) || (memcmp(emp8, kaes+24, 8) != 0))
{
memcpy(ob, kaes, 32);
klen = 32;
}
//test for 32 char (16 byte) key
else if ((memcmp(emp8, kaes+8, 8) != 0))
{
memcpy(ob, kaes, 16);
klen = 16;
}
//this is a 10 char (5 byte) key w/ offset
else
{
memcpy(ob, kaes+3, 5);
klen = 5;
}
end += (poc + 4); //also perform application over padding bytes and crc value
for (i = 0; i < end; i++)
state->dmr_pdu_sf[slot][i+start] ^= ob[i%klen];
decrypted_pdu = 1;
//Recalcuate CRC32
uint8_t reordered_bits[1000];
memset (reordered_bits, 0, sizeof(reordered_bits));
//rearrage for ridiculously stupid CRC32 LSO/MSO ordering
for(i = 0, j = 0; i < ctr; i+=2, j+=16)
{
reordered_bits[j + 0] = (state->dmr_pdu_sf[slot][i+1] >> 7) & 0x01;
reordered_bits[j + 1] = (state->dmr_pdu_sf[slot][i+1] >> 6) & 0x01;
reordered_bits[j + 2] = (state->dmr_pdu_sf[slot][i+1] >> 5) & 0x01;
reordered_bits[j + 3] = (state->dmr_pdu_sf[slot][i+1] >> 4) & 0x01;
reordered_bits[j + 4] = (state->dmr_pdu_sf[slot][i+1] >> 3) & 0x01;
reordered_bits[j + 5] = (state->dmr_pdu_sf[slot][i+1] >> 2) & 0x01;
reordered_bits[j + 6] = (state->dmr_pdu_sf[slot][i+1] >> 1) & 0x01;
reordered_bits[j + 7] = (state->dmr_pdu_sf[slot][i+1] >> 0) & 0x01;
reordered_bits[j + 8] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
reordered_bits[j + 9] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
reordered_bits[j + 10] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
reordered_bits[j + 11] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
reordered_bits[j + 12] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
reordered_bits[j + 13] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
reordered_bits[j + 14] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
reordered_bits[j + 15] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
}
CRCComputed = (uint32_t)ComputeCrc32BitV(reordered_bits, (ctr * 8) - 32);
CRCExtracted = (uint32_t)convert_bits_into_output(reordered_bits+((ctr * 8) - 32), 32);
if (CRCComputed == CRCExtracted)
CRCCorrect = 1;
else CRCCorrect = 0;
//set back to original value
end -= (poc + 4);
//debug
// fprintf (stderr, " CTR: %d; CRC32 CMP: %08X EXT: %08X", ctr, CRCComputed, CRCExtracted);
} }
else if (alg == 0xD0 && R != 0) //Hytera Enhanced RC4 else if (alg == 0xD0) //Hytera Enhanced RC4
{ {
//TODO: Test this with any samples if we ever see one //just passing through to see if a key was loaded and the blocks decrypted
//also, will need to make more ks with a len option in function decrypted_pdu = hytera_ep_data_decrypt(opts, state, empt, 1);
//currently, only have enough for 7.5 R34 data blocks tops
hytera_enhanced_rc4_setup(opts, state, R, mi);
if (slot == 0)
memcpy(ob, state->ks_octetL, 135);
else memcpy(ob, state->ks_octetR, 135);
end += (poc + 4); //also perform application over padding bytes and crc value
for (i = 0; i < end; i++)
state->dmr_pdu_sf[slot][i+start] ^= ob[i];
decrypted_pdu = 1;
//Recalcuate CRC32
uint8_t reordered_bits[1000];
memset (reordered_bits, 0, sizeof(reordered_bits));
//rearrage for ridiculously stupid CRC32 LSO/MSO ordering
for(i = 0, j = 0; i < ctr; i+=2, j+=16)
{
reordered_bits[j + 0] = (state->dmr_pdu_sf[slot][i+1] >> 7) & 0x01;
reordered_bits[j + 1] = (state->dmr_pdu_sf[slot][i+1] >> 6) & 0x01;
reordered_bits[j + 2] = (state->dmr_pdu_sf[slot][i+1] >> 5) & 0x01;
reordered_bits[j + 3] = (state->dmr_pdu_sf[slot][i+1] >> 4) & 0x01;
reordered_bits[j + 4] = (state->dmr_pdu_sf[slot][i+1] >> 3) & 0x01;
reordered_bits[j + 5] = (state->dmr_pdu_sf[slot][i+1] >> 2) & 0x01;
reordered_bits[j + 6] = (state->dmr_pdu_sf[slot][i+1] >> 1) & 0x01;
reordered_bits[j + 7] = (state->dmr_pdu_sf[slot][i+1] >> 0) & 0x01;
reordered_bits[j + 8] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
reordered_bits[j + 9] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
reordered_bits[j + 10] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
reordered_bits[j + 11] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
reordered_bits[j + 12] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
reordered_bits[j + 13] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
reordered_bits[j + 14] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
reordered_bits[j + 15] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
}
CRCComputed = (uint32_t)ComputeCrc32BitV(reordered_bits, (ctr * 8) - 32);
CRCExtracted = (uint32_t)convert_bits_into_output(reordered_bits+((ctr * 8) - 32), 32);
if (CRCComputed == CRCExtracted)
CRCCorrect = 1;
else CRCCorrect = 0;
//set back to original value
end -= (poc + 4);
//debug
// fprintf (stderr, " CTR: %d; CRC32 CMP: %08X EXT: %08X", ctr, CRCComputed, CRCExtracted);
} }
else if (alg == 7 && state->vtx_key_loaded == 1) //Vertex Standard, either enc type else if (alg == 7 && state->vtx_key_loaded == 1) //Vertex Standard, either enc type
@@ -1825,4 +1706,12 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
// sprintf (state->call_string[1], "%s", " "); //21 spaces // sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->dmr_lrrp_gps[0], "%s", ""); sprintf (state->dmr_lrrp_gps[0], "%s", "");
sprintf (state->dmr_lrrp_gps[1], "%s", ""); sprintf (state->dmr_lrrp_gps[1], "%s", "");
//Hytera OTA Encryption
memset(state->hota_lc_ctx, 0, sizeof(state->hota_lc_ctx));
memset(state->hota_ctx_ok, 0, sizeof(state->hota_ctx_ok));
state->hota_sbrc_idx1[0] = -1;
state->hota_sbrc_idx2[0] = -1;
state->hota_sbrc_idx1[1] = -1;
state->hota_sbrc_idx2[1] = -1;
} }

View File

@@ -462,6 +462,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
if (internalslot == 0 && vc1 == 6) if (internalslot == 0 && vc1 == 6)
{ {
if (state->hota_enc_check && state->forced_alg_id > 1)
{
state->dmr_so = 0x40;
state->payload_algid = state->forced_alg_id;
state->payload_keyid = 0xFF;
}
//this needs to run prior to embedded link control //this needs to run prior to embedded link control
if (state->payload_algid == 0x02) if (state->payload_algid == 0x02)
hytera_enhanced_alg_refresh(state); hytera_enhanced_alg_refresh(state);
@@ -475,6 +481,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
if (internalslot == 1 && vc2 == 6) if (internalslot == 1 && vc2 == 6)
{ {
if (state->hota_enc_check && state->forced_alg_id > 1)
{
state->dmr_soR = 0x40;
state->payload_algidR = state->forced_alg_id;
state->payload_keyidR = 0xFF;
}
//this needs to run prior to embedded link control //this needs to run prior to embedded link control
if (state->payload_algidR == 0x02) if (state->payload_algidR == 0x02)
hytera_enhanced_alg_refresh(state); hytera_enhanced_alg_refresh(state);

View File

@@ -55,6 +55,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
memset (DMR_PDU, 0, sizeof (DMR_PDU)); memset (DMR_PDU, 0, sizeof (DMR_PDU));
memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits)); memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits));
uint8_t hota_enc = 0;
uint8_t is_ras = 0; uint8_t is_ras = 0;
uint8_t bptc_res_bits[3]; uint8_t bptc_res_bits[3];
memset (bptc_res_bits, 0, sizeof(bptc_res_bits)); memset (bptc_res_bits, 0, sizeof(bptc_res_bits));
@@ -76,6 +77,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
switch(databurst){ switch(databurst){
case 0x00: //PI case 0x00: //PI
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
crclen = 16; crclen = 16;
crcmask = 0x6969; //insert pi and 69 jokes here crcmask = 0x6969; //insert pi and 69 jokes here
@@ -83,6 +85,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
sprintf(state->fsubtype, " PI "); sprintf(state->fsubtype, " PI ");
break; break;
case 0x01: //VLC case 0x01: //VLC
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
is_lc = 1; is_lc = 1;
crclen = 24; crclen = 24;
@@ -91,6 +94,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
sprintf(state->fsubtype, " VLC "); sprintf(state->fsubtype, " VLC ");
break; break;
case 0x02: //TLC case 0x02: //TLC
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
is_lc = 1; is_lc = 1;
crcmask = 0x999999; crcmask = 0x999999;
@@ -99,6 +103,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
sprintf(state->fsubtype, " TLC "); sprintf(state->fsubtype, " TLC ");
break; break;
case 0x03: //CSBK case 0x03: //CSBK
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
crclen = 16; crclen = 16;
crcmask = 0xA5A5; crcmask = 0xA5A5;
@@ -106,6 +111,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
sprintf(state->fsubtype, " CSBK"); sprintf(state->fsubtype, " CSBK");
break; break;
case 0x04: //MBC Header case 0x04: //MBC Header
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
crclen = 16; crclen = 16;
crcmask = 0xAAAA; crcmask = 0xAAAA;
@@ -119,6 +125,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
sprintf(state->fsubtype, " MBCC"); sprintf(state->fsubtype, " MBCC");
break; break;
case 0x06: //Data Header case 0x06: //Data Header
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
crclen = 16; crclen = 16;
crcmask = 0xCCCC; crcmask = 0xCCCC;
@@ -176,6 +183,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
} }
break; break;
case 0x0B: //Unified Single Block Data USBD case 0x0B: //Unified Single Block Data USBD
hota_enc = 1;
is_bptc = 1; is_bptc = 1;
crclen = 16; crclen = 16;
crcmask = 0x3333; crcmask = 0x3333;
@@ -185,6 +193,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
//special types (not real data 'sync' bursts) //special types (not real data 'sync' bursts)
case 0xEB: //Embedded Signalling case 0xEB: //Embedded Signalling
hota_enc = 1;
crclen = 5; crclen = 5;
is_emb = 1; is_emb = 1;
pdu_len = 9; pdu_len = 9;
@@ -254,6 +263,23 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
fprintf (stderr, " BPTC R BITS: %d %d %d", bptc_res_bits[0], bptc_res_bits[1], bptc_res_bits[2]); fprintf (stderr, " BPTC R BITS: %d %d %d", bptc_res_bits[0], bptc_res_bits[1], bptc_res_bits[2]);
#endif #endif
//TODO: Checkdown no irrecoverable errors prior to OTA Decryption?
//Hytera OTA Encryption
if (state->hota_key_loaded && hota_enc)
hytera_ota_decrypt_bptc_96(state, BPTCDmrDataBit, databurst);
//Hytera Data Block Level Decryption
if (databurst == 0x7) //Rate 1_2 Data Only
{
uint8_t bytes[12];
memset(bytes, 0, sizeof(bytes));
pack_bit_array_into_byte_array(BPTCDmrDataBit, bytes, 12);
hytera_bp_data_decrypt(state, bytes, 12);
hytera_ep_data_decrypt(opts, state, bytes, 12);
unpack_byte_array_into_bit_array(bytes, BPTCDmrDataBit, 12);
}
/* Convert the 96 bits BPTC data into 12 bytes */ /* Convert the 96 bits BPTC data into 12 bytes */
pack_bit_array_into_byte_array(BPTCDmrDataBit, BPTCDmrDataByte, 12); pack_bit_array_into_byte_array(BPTCDmrDataBit, BPTCDmrDataByte, 12);
@@ -288,6 +314,10 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
#endif #endif
} }
else CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask); else CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
//Hytera OTA Encryption LC Context Creation for VLC Header
if (state->hota_key_loaded && CRCCorrect && databurst == 0x01)
hytera_create_lc_ctx(state, BPTCDmrDataBit);
} }
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these) //set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
@@ -400,8 +430,42 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
} /* End for(j = 0; j < 8; j++) */ } /* End for(j = 0; j < 8; j++) */
} /* End for(i = 0; i < 16; i++) */ } /* End for(i = 0; i < 16; i++) */
//Hytera OTA Encryption
// if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 0)
// hytera_ota_search_emb_lc(state, BptcDataMatrix); //only run as a debug option
if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 1)
hytera_ota_decrypt_emb_lc(state, BptcDataMatrix);
/* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */ /* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */
IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit); if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 0)
{
//just fill with all ones, would be garbage from FEC anyways
memset(LC_DataBit, 1, sizeof(LC_DataBit));
IrrecoverableErrors = 1;
//TODO: columns instead of rows to match application of keystream
#ifdef DEBUG_HOTA
fprintf(stderr, "\n BPTC 128: ");
for (int i = 0; i < 8; i++)
fprintf (stderr, "%04X", (uint16_t)convert_bits_into_output(BptcDataMatrix[i], 16));
fprintf (stderr, "\n");
#endif
}
else if (state->hota_enc_check == 1)
{
//just fill with all ones, would be garbage from FEC anyways
memset(LC_DataBit, 1, sizeof(LC_DataBit));
IrrecoverableErrors = 1;
//TODO: columns instead of rows to match application of keystream
#ifdef DEBUG_HOTA
fprintf(stderr, "\n BPTC 128: ");
for (int i = 0; i < 8; i++)
fprintf (stderr, "%04X", (uint16_t)convert_bits_into_output(BptcDataMatrix[i], 16));
fprintf (stderr, "\n");
#endif
}
else IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit);
/* Reconstitute the 5 bit CRC */ /* Reconstitute the 5 bit CRC */
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5); CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5);
@@ -452,6 +516,10 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
memset (TrellisReturn, 0, sizeof(TrellisReturn)); memset (TrellisReturn, 0, sizeof(TrellisReturn));
IrrecoverableErrors = viterbi_r34(tdibits, TrellisReturn); IrrecoverableErrors = viterbi_r34(tdibits, TrellisReturn);
//Hytera Data Block Level Decryption
hytera_bp_data_decrypt(state, TrellisReturn, 18);
hytera_ep_data_decrypt(opts, state, TrellisReturn, 18);
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis //NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
//they may have been successfully corrected, the CRC will reveal as much //they may have been successfully corrected, the CRC will reveal as much
@@ -530,6 +598,10 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
bit_ptr = 100; byte_ptr = 12-pdu_start; bit_ptr = 100; byte_ptr = 12-pdu_start;
pack_bit_array_into_byte_array (info+bit_ptr, DMR_PDU+byte_ptr, 12); pack_bit_array_into_byte_array (info+bit_ptr, DMR_PDU+byte_ptr, 12);
//Hytera Data Block Level Decryption
hytera_bp_data_decrypt(state, DMR_PDU, 24);
hytera_ep_data_decrypt(opts, state, DMR_PDU, 24);
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these) //set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
if (state->data_conf_data[slot] == 0) CRCCorrect = 1; if (state->data_conf_data[slot] == 0) CRCCorrect = 1;

View File

@@ -76,10 +76,65 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
//Kirisun //Kirisun
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40 if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40
{ {
//disable late entry for DMRA, Flag 3 if encrypted, 0 if not //disable late entry for DMRA, Flag 3 if encrypted, 0 if not
if (so & 0x40) if (so & 0x40)
opts->dmr_le = 3; opts->dmr_le = 3;
else opts->dmr_le = 0; else opts->dmr_le = 0;
}
//Hytera OTA Check Enabled, Set SRC from VLC (TLC and ELC differ)
//NOTE: VLC will always be same for each radio if its a group call
//while this is not the true src, it should be unique
//TGT will also be random between calls in each VLC,
//so assign static value
if (state->hota_enc_check)
{
if (type == 1)
{
if (slot == 0)
{
state->lastsrc = source;
state->lasttg = 8686868;
}
else
{
state->lastsrcR = source;
state->lasttgR = 8686868;
}
fprintf (stderr, "\n%s", KYEL);
fprintf (stderr, " SLOT %d ", slot+1);
fprintf(stderr, "TGT=%u SRC=%u ", state->lasttg, source);
fprintf (stderr, "Forced Pseudo Call Information");
fprintf (stderr, "%s", KNRM);
return;
}
else if (type == 2)
{
fprintf (stderr, "\n%s", KRED);
fprintf (stderr, " SLOT %d", slot+1);
fprintf (stderr, " TLC Undecryptable;");
fprintf (stderr, "%s", KNRM);
return;
}
else if (type == 3)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " SLOT %d", slot+1);
fprintf (stderr, " EMB LC Undecryptable;");
fprintf (stderr, "%s", KNRM);
return;
}
}
//HOTA CTX was not recovered, so dump that and return;
else if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 0 && type == 3)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " SLOT %d", slot+1);
fprintf (stderr, " EMB LC Missing CTX; Undecryptable;");
fprintf (stderr, "%s", KNRM);
return;
} }
//read ahead a little to get this for the xpt flag //read ahead a little to get this for the xpt flag
@@ -486,6 +541,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
sprintf (state->generic_talker_alias[0], "%s", ""); sprintf (state->generic_talker_alias[0], "%s", "");
// sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA"); // sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0])); memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
//Hytera OTA Encryption
memset(state->hota_lc_ctx[0], 0, sizeof(state->hota_lc_ctx[0]));
state->hota_ctx_ok[0] = 0;
state->hota_sbrc_idx1[0] = -1;
state->hota_sbrc_idx2[0] = -1;
} }
if (state->currentslot == 1) if (state->currentslot == 1)
{ {
@@ -506,6 +567,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
sprintf (state->generic_talker_alias[1], "%s", ""); sprintf (state->generic_talker_alias[1], "%s", "");
// sprintf (state->event_history_s[1].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA"); // sprintf (state->event_history_s[1].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
memset (state->dmr_pdu_sf[1], 0, sizeof(state->dmr_pdu_sf[1])); memset (state->dmr_pdu_sf[1], 0, sizeof(state->dmr_pdu_sf[1]));
//Hytera OTA Encryption
memset(state->hota_lc_ctx[1], 0, sizeof(state->hota_lc_ctx[1]));
state->hota_ctx_ok[1] = 0;
state->hota_sbrc_idx1[1] = -1;
state->hota_sbrc_idx2[1] = -1;
} }
} }

View File

@@ -8,6 +8,9 @@
#include "dsd.h" #include "dsd.h"
static unsigned long long int next_iv_32[2] = {0,0};
static unsigned long long int next_iv_64[2] = {0,0};
//gather ambe_fr mi fragments for processing //gather ambe_fr mi fragments for processing
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24]) void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24])
{ {
@@ -86,6 +89,95 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
if (g[0] && g[1] && g[2]) if (g[0] && g[1] && g[2])
{ {
if (mi_crc_ok == 1 && state->hota_enc_check == 1)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot %d DMRA EP Potential;", slot+1);
unsigned long long int temp_iv = mi_final;
//Reverse Potential IV for both 32-bit and 128-bit to show the IV
//that may have been carried by the PI header or last superframe
uint8_t iv_a[16]; memset(iv_a, 0, sizeof(iv_a));
uint8_t iv_d[16]; memset(iv_d, 0, sizeof(iv_d));
for (int i = 0; i < 4; i++)
{
iv_a[i] = (mi_final >> (24-(i*8))) & 0xFF;
iv_d[i] = (mi_final >> (24-(i*8))) & 0xFF;
}
fprintf (stderr, "\n ");
reverse_lfsr_32a_to_len(iv_a, 32);
fprintf (stderr, " ");
reverse_lfsr_32d_to_len(iv_d, 32);
fprintf (stderr, "\n");
if (next_iv_64[slot] != 0 && mi_final == next_iv_64[slot])
{
//probably safe to assume AES-256 if its DMRA specific
fprintf (stderr, " DMRA AES 128-bit IV detected;");
state->forced_alg_id = 0x25;
if (slot == 0 && state->payload_mi == 0)
{
fprintf (stderr, "\n");
state->payload_mi = mi_final;
state->dmr_so = 0x40;
LFSR128d(state);
}
else if (slot == 1 && state->payload_miR == 0)
{
fprintf (stderr, "\n");
state->payload_miR = mi_final;
state->dmr_soR = 0x40;
LFSR128d(state);
}
}
if (next_iv_32[slot] != 0 && mi_final == next_iv_32[slot])
{
//only DMRA RC4 uses this tap configuration
fprintf (stderr, " DMRA RC4 32-bit IV detected;");
state->forced_alg_id = 0x21;
if (slot == 0 && state->payload_mi == 0)
{
fprintf (stderr, "\n");
state->payload_mi = mi_final;
state->dmr_so = 0x40;
LFSR(state);
}
else if (slot == 1 && state->payload_miR == 0)
{
fprintf (stderr, "\n");
state->payload_miR = mi_final;
state->dmr_soR = 0x40;
LFSR(state);
}
}
//AES taps to next embedded value
for(int cnt = 0; cnt < 32; cnt++)
{
unsigned long long int bit = ( (temp_iv >> 31) ^ (temp_iv >> 21) ^ (temp_iv >> 1) ^ (temp_iv >> 0) ) & 0x1;
temp_iv = (temp_iv << 1) | bit;
}
next_iv_64[slot] = temp_iv & 0xFFFFFFFF;
//RC4 taps to next embedded value
temp_iv = mi_final;
for(int cnt = 0; cnt < 32; cnt++)
{
unsigned long long int bit = ( (temp_iv >> 31) ^ (temp_iv >> 3) ^ (temp_iv >> 1) ) & 0x1;
temp_iv = (temp_iv << 1) | bit;
}
next_iv_32[slot] = temp_iv & 0xFFFFFFFF;
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
if (slot == 0 && state->payload_algid != 0 && state->payload_algid != 0x26) if (slot == 0 && state->payload_algid != 0 && state->payload_algid != 0x26)
{ {
if (state->payload_mi != mi_final) if (state->payload_mi != mi_final)
@@ -365,6 +457,13 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
// 1 - The embedded signalling carries RC information associated to the other logical channel // 1 - The embedded signalling carries RC information associated to the other logical channel
for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8]; for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8];
//decrypt for Hytera OTA Encryption w/ loaded key
if (state->hota_key_loaded && state->hota_sbrc_idx1[state->currentslot] == -1)
hytera_ota_search_sb_rc(state, sbrc_interleaved, power);
if (state->hota_key_loaded)
hytera_ota_decrypt_sb_rc(state, sbrc_interleaved);
//power == 0 should be single burst //power == 0 should be single burst
if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0); if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0);
//power == 1 should be reverse channel -- still need to check the interleave inside of BPTC //power == 1 should be reverse channel -- still need to check the interleave inside of BPTC
@@ -372,6 +471,36 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
//bad emb burst, never set a valid power indicator value (probably 9) //bad emb burst, never set a valid power indicator value (probably 9)
if (power > 1) goto SBRC_END; if (power > 1) goto SBRC_END;
//Hytera OTA
if (irr_err && state->hota_key_loaded && state->hota_sbrc_idx2[state->currentslot] == -1)
{
state->hota_sbrc_idx1[state->currentslot] = -1;
state->hota_sbrc_idx2[state->currentslot] = -1;
fprintf (stderr, "%s \n", KRED);
fprintf (stderr, " SLOT %d ", slot+1);
fprintf (stderr, "SB_RC Missing IDX; Undecryptable;");
fprintf (stderr, "%s\n", KNRM);
goto SBRC_END;
}
else if (irr_err && state->hota_key_loaded && state->hota_sbrc_idx2[state->currentslot] != -1)
{
state->hota_sbrc_idx1[state->currentslot] = -1;
state->hota_sbrc_idx2[state->currentslot] = -1;
fprintf (stderr, "%s \n", KRED);
fprintf (stderr, " SLOT %d ", slot+1);
fprintf (stderr, "SB_RC Incorrect IDX or FEC Errors; Undecryptable;");
fprintf (stderr, "%s\n", KNRM);
goto SBRC_END;
}
else if (state->hota_enc_check)
{
fprintf (stderr, "%s \n", KRED);
fprintf (stderr, " SLOT %d ", slot+1);
fprintf (stderr, "SB_RC Undecryptable;");
fprintf (stderr, "%s\n", KNRM);
goto SBRC_END;
}
//arrange the return for proper order for the crc3 check //arrange the return for proper order for the crc3 check
for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3]; for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3];

View File

@@ -877,6 +877,76 @@ void unpack_ambe (uint8_t * input, char * ambe)
ambe[48] = input[6] >> 7; ambe[48] = input[6] >> 7;
} }
uint64_t reverse_lfsr_32a_to_len(uint8_t * iv, int16_t len)
{
uint64_t lfsr = 0, bit1 = 0, bit2 = 0;
lfsr = ((uint64_t)iv[0] << 24ULL) + ((uint64_t)iv[1] << 16ULL) + ((uint64_t)iv[2] << 8ULL) + ((uint64_t)iv[3] << 0ULL);
memset (iv, 0, 8*sizeof(uint8_t));
for(int16_t cnt = 0; cnt < len; cnt++)
{
//32,22,2,1 (per Xilinx XAPP 052) Table 3: Taps for Maximum-Length LFSR Counters
//taps at the +1 position on all but MSB, then check the LSB and configure bit as required
bit1 = ( (lfsr >> 22) ^ (lfsr >> 2) ^ (lfsr >> 1) ) & 0x1;
bit2 = lfsr & 1;
if (bit1 == bit2)
bit2 = 0;
else bit2 = 1;
//just run this in reverse of normal LFSR
lfsr = (lfsr >> 1) | (bit2 << 31);
}
for (int16_t i = 0; i < 4; i++)
iv[i] = (lfsr >> (24-(i*8))) & 0xFF;
fprintf (stderr, "REV LFSR AES(%02d): ", len);
for (int16_t i = 0; i < 4; i++)
fprintf (stderr, "%02X", iv[i]);
return bit2;
}
uint64_t reverse_lfsr_32d_to_len(uint8_t * iv, int16_t len)
{
uint64_t lfsr = 0, bit1 = 0, bit2 = 0;
lfsr = ((uint64_t)iv[0] << 24ULL) + ((uint64_t)iv[1] << 16ULL) + ((uint64_t)iv[2] << 8ULL) + ((uint64_t)iv[3] << 0ULL);
memset (iv, 0, 8*sizeof(uint8_t));
for(int16_t cnt = 0; cnt < len; cnt++)
{
//magical taps that somebody must have dreamt up
//taps at the +1 position on all but MSB, then check the LSB and configure bit as required
bit1 = ((lfsr >> 4) ^ (lfsr >> 2)) & 0x1;
bit2 = lfsr & 1;
if (bit1 == bit2)
bit2 = 0;
else bit2 = 1;
//just run this in reverse of normal LFSR
lfsr = (lfsr >> 1) | (bit2 << 31);
}
for (int16_t i = 0; i < 4; i++)
iv[i] = (lfsr >> (24-(i*8))) & 0xFF;
fprintf (stderr, "REV LFSR RC4(%02d): ", len);
for (int16_t i = 0; i < 4; i++)
fprintf (stderr, "%02X", iv[i]);
return bit2;
}
//recover previous IV for SDRTrunk .mbe files when P25p1 //recover previous IV for SDRTrunk .mbe files when P25p1
uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len) uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len)
{ {

View File

@@ -528,7 +528,7 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
if (slot == 1) src = state->lasttgR; if (slot == 1) src = state->lasttgR;
//save to event history string //save to event history string
if (state->event_history_s[slot].Event_History_Items[0].source_id == src) // if (state->event_history_s[slot].Event_History_Items[0].source_id == src)
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]); sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
//save to LRRP report for mapping/logging //save to LRRP report for mapping/logging

View File

@@ -585,6 +585,14 @@
//we do reset the counter, but not the static_ks_bits //we do reset the counter, but not the static_ks_bits
memset (state->static_ks_counter, 0, sizeof(state->static_ks_counter)); memset (state->static_ks_counter, 0, sizeof(state->static_ks_counter));
//Hytera OTA Encryption
memset(state->hota_lc_ctx, 0, sizeof(state->hota_lc_ctx));
memset(state->hota_ctx_ok, 0, sizeof(state->hota_ctx_ok));
state->hota_sbrc_idx1[0] = -1;
state->hota_sbrc_idx2[0] = -1;
state->hota_sbrc_idx1[1] = -1;
state->hota_sbrc_idx2[1] = -1;
} //nocarrier } //nocarrier
@@ -1245,6 +1253,21 @@
memset (state->ras_permutation_order, 0, sizeof(state->ras_permutation_order)); memset (state->ras_permutation_order, 0, sizeof(state->ras_permutation_order));
state->ras_effective_key = 0; state->ras_effective_key = 0;
state->dmr_is_ras = 0; state->dmr_is_ras = 0;
//Hytera OTA Encryption
state->hota_enc_check = 0;
state->hota_key_loaded = 0;
state->dmr_is_hota = 0;
state->hota_bit_shift = 0;
memset(state->hota_byte_shifts, 0, sizeof(state->hota_byte_shifts));
memset(state->hota_rc4_key, 0, sizeof(state->hota_rc4_key));
memset(state->hota_rc4_ks, 0, sizeof(state->hota_rc4_ks));
memset(state->hota_lc_ctx, 0, sizeof(state->hota_lc_ctx));
memset(state->hota_ctx_ok, 0, sizeof(state->hota_ctx_ok));
state->hota_sbrc_idx1[0] = -1;
state->hota_sbrc_idx2[0] = -1;
state->hota_sbrc_idx1[1] = -1;
state->hota_sbrc_idx2[1] = -1;
sprintf (state->dmr_branding, "%s", ""); sprintf (state->dmr_branding, "%s", "");
sprintf (state->dmr_branding_sub, "%s", ""); sprintf (state->dmr_branding_sub, "%s", "");
@@ -1561,6 +1584,10 @@
printf (" -H C:128:736B9A9C5645288B243AD5CB8701EF8A' \n"); printf (" -H C:128:736B9A9C5645288B243AD5CB8701EF8A' \n");
printf (" -H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8' \n"); printf (" -H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8' \n");
printf ("\n"); printf ("\n");
printf (" -H <hex> Manually Enter Hytera OTA Encryption 32 Char Hex Key (see example below)\n");
printf (" -H O:0:0 no keystream application, but check for Hytera OTA Encryption and DMRA EP Late Entry IV.\n");
printf (" -H O:128:17bfe59b29a06136fb7d3811fd1a4904 for 128-bit RC4 OTA Key Setup\n");
printf ("\n");
printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n"); printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
printf (" \n"); printf (" \n");
printf (" -1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n"); printf (" -1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n");
@@ -2296,11 +2323,16 @@
break; break;
case 'H': case 'H':
//check for caltta, if not, then use older loader //check for caltta bp key load
if (optarg[0] == 'C' && optarg[1] == ':') if (optarg[0] == 'C' && optarg[1] == ':')
{ {
caltta_bp_keystream_creation(&state, optarg+2); caltta_bp_keystream_creation(&state, optarg+2);
} }
//check for Hytera OTA key load
else if (optarg[0] == 'O' && optarg[1] == ':')
{
hytera_ota_keystream_setup(&state, optarg+2);
}
else else
{ {
strncpy(opts.szNumbers, optarg, 1023); strncpy(opts.szNumbers, optarg, 1023);
@@ -2309,7 +2341,12 @@
state.K2 = strtoull (pEnd, &pEnd, 16); state.K2 = strtoull (pEnd, &pEnd, 16);
state.K3 = strtoull (pEnd, &pEnd, 16); state.K3 = strtoull (pEnd, &pEnd, 16);
state.K4 = strtoull (pEnd, &pEnd, 16); state.K4 = strtoull (pEnd, &pEnd, 16);
fprintf (stderr, "Hytera40/128/256 BP or AES128/256 Key = %016llX %016llX %016llX %016llX\n", state.K1, state.K2, state.K3, state.K4); if (state.K2 == 0 && state.K3 == 0 && state.K4 == 0)
fprintf (stderr, "Hytera BP 40-bit Key: %010llX\n", state.K1);
else if (state.K2 != 0)
fprintf (stderr, "Multi 128-bit Key: %016llX%016llX\n", state.K1, state.K2);
else
fprintf (stderr, "Multi 256-bit Key: %016llX%016llX%016llX%016llX\n", state.K1, state.K2, state.K3, state.K4);
opts.dmr_mute_encL = 0; opts.dmr_mute_encL = 0;
opts.dmr_mute_encR = 0; opts.dmr_mute_encR = 0;
if (state.K1 == 0 && state.K2 == 0 && state.K3 == 0 && state.K4 == 0) if (state.K1 == 0 && state.K2 == 0 && state.K3 == 0 && state.K4 == 0)

View File

@@ -813,7 +813,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
if(state->payload_algid == 0x02) if(state->payload_algid == 0x02)
{ {
n = 0; n = 0;
hytera_enhanced_rc4_setup(opts, state, state->R, state->payload_mi); hytera_enhanced_rc4_setup(opts, state, state->R, state->payload_mi, 135);
} }
if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A) if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A)
{ {
@@ -1313,7 +1313,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
if(state->payload_algidR == 0x02) if(state->payload_algidR == 0x02)
{ {
n = 0; n = 0;
hytera_enhanced_rc4_setup(opts, state, state->RR, state->payload_miR); hytera_enhanced_rc4_setup(opts, state, state->RR, state->payload_miR, 135);
} }
if (state->payload_algidR >= 0x31 && state->payload_algidR <= 0x3A) if (state->payload_algidR >= 0x31 && state->payload_algidR <= 0x3A)
{ {

View File

@@ -325,9 +325,6 @@ void rs_12_9_encode(uint8_t * input)
//init cw //init cw
memset(cw.data, 0, 12*sizeof(uint8_t)); memset(cw.data, 0, 12*sizeof(uint8_t));
//init cs
memset(cs->bytes, 0, 3*sizeof(uint8_t));
//Copy 9 bytes of data input //Copy 9 bytes of data input
memcpy(cw.data, input, 9); memcpy(cw.data, input, 9);