From bfa4891965c6fa848ba007bb85cbe840746b4316 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Fri, 6 Nov 2026 21:22:38 -0500 Subject: [PATCH] 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; --- .../cygwin_bat/complete_usage_options.txt | 4 + include/dsd.h | 36 +- src/bptc.c | 362 ++++-- src/crypt-aes.c | 2 +- src/crypt-rc4.c | 1133 ++++++++++++++++- src/dmr_block.c | 139 +- src/dmr_bs.c | 12 + src/dmr_dburst.c | 74 +- src/dmr_flco.c | 75 +- src/dmr_le.c | 129 ++ src/dsd_file.c | 70 + src/dsd_gps.c | 2 +- src/dsd_main.c | 41 +- src/dsd_mbe.c | 4 +- src/rs-12-9.c | 3 - 15 files changed, 1825 insertions(+), 261 deletions(-) diff --git a/examples/cygwin_bat/complete_usage_options.txt b/examples/cygwin_bat/complete_usage_options.txt index ea8191e..c33ce88 100644 --- a/examples/cygwin_bat/complete_usage_options.txt +++ b/examples/cygwin_bat/complete_usage_options.txt @@ -152,6 +152,10 @@ Advanced Decoder options: -H C:128:736B9A9C5645288B243AD5CB8701EF8A' -H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8' + -H 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 Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value) -1 Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) diff --git a/include/dsd.h b/include/dsd.h index eb89975..b917b43 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -935,6 +935,20 @@ typedef struct int ras_permutation_order[104]; 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 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_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_128x77_Check_Errors(uint8_t InputDataMatrix[8][16]); //Reed Solomon DMR functions 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 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_encode(unsigned char *origBits, unsigned char *encodedBits); 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); //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); 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_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 void lfsr_32_to_128(uint8_t * iv); void lfsr_64_to_128(uint8_t * iv); diff --git a/src/bptc.c b/src/bptc.c index e96fbab..04ce9a5 100644 --- a/src/bptc.c +++ b/src/bptc.c @@ -167,197 +167,283 @@ void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output) /* - * @brief : This function extract the 96 bits of a deinteleaved 196 bits - * buffer using BPTC (196,96) - * - * @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 + * BPTC (196,96) extract — ETSI TS 102 361-1 B.1.1 + * Two-pass row Hamming(15,11) + column Hamming(13,9). + * Debug: define BPTC_196x96_DEBUG 1 for row/col correction chatter. */ -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; uint8_t DataMatrix[13][15]; uint8_t LineUncorrected[15]; + uint8_t LineBefore[15]; uint8_t LineCorrected[11]; uint8_t ColumnUncorrected[13]; + uint8_t ColumnBefore[13]; uint8_t ColumnCorrected[9]; 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 - * Note : Input data shall be deinterleaved */ - k = 1; /* Discard R(3) bit - See DMR standard chapter B1.1 BPTC (196,96) */ - for(i = 0; i < 13; i++) + UNUSED(row_corr_p1); UNUSED(col_corr_p1); + UNUSED(row_fail_p1); UNUSED(col_fail_p1); + UNUSED(row_corr_p2); UNUSED(col_corr_p2); + 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); k++; } } - /* Process the the Hamming (15,11,3) code - * check on each line (first time). - * Do not check the 4th last lines */ - for(i = 0; i < 9; i++) + /* ========== Pass 1: row Hamming(15,11) on rows 0..8 ========== */ + 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]; + 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++; + 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]; } - - /* 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++) + else { - 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 - - /* Process the the Hamming (15,11,3) code - * check on each column/row (first time) */ - for(i = 0; i < 15; i++) + /* ========== Pass 1: column Hamming(13,9) on cols 0..14 ========== */ + 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]; + 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++; + 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]; } - - /* 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++) + else { - 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 - * which can be use to correct other bit, so make the - * same operation twice */ - - /* Reset the number of irrecoverable errors */ + /* Second pass can fix more after the first cascade */ HammingIrrecoverableErrorNb = 0; - - /* Process the the Hamming (15,11,3) code - * check on each line (second time). - * Do not check the 4th last lines */ - for(i = 0; i < 9; i++) + /* ========== Pass 2: rows ========== */ + 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]; + 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++; + 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 { - /* Row/Line contains correct data */ - } - - /* 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]; + for (j = 0; j < 15; j++) + { + if ((LineBefore[j] & 1) != (LineUncorrected[j] & 1)) + { + row_corr_p2++; +#if BPTC_196x96_DEBUG + fprintf(stderr, + " 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 - - /* Process the the Hamming (15,11,3) code - * check on each column/row (second time) */ - for(i = 0; i < 15; i++) + /* ========== Pass 2: columns ========== */ + 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]; + 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++; + 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 { - /* Row/Line contains correct data */ - } - - /* 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_p2++; +#if BPTC_196x96_DEBUG + fprintf(stderr, + " 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 */ - /* First line : Do not take R(2), R(1) and R(0) */ + /* Extract 96 data bits */ k = 0; - - for(i = 3; i < 11; i++) + for (i = 3; i < 11; i++) { - DMRDataExtracted[k] = DataMatrix[0][i]; - k++; + DMRDataExtracted[k++] = DataMatrix[0][i]; + } + 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) { - R[0] = DataMatrix[0][2]; /* Save R(0) */ - R[1] = DataMatrix[0][1]; /* Save R(1) */ - R[2] = DataMatrix[0][0]; /* Save R(2) */ + R[0] = DataMatrix[0][2]; /* R(0) */ + R[1] = DataMatrix[0][1]; /* R(1) */ + 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; -} /* 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 col_bad[16]; +#if BPTC_128x77_DEBUG + fprintf (stderr, "\n"); +#endif + for (i = 0; i < 8; i++) { 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() */ +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 */ diff --git a/src/crypt-aes.c b/src/crypt-aes.c index 46a436a..b7af7ba 100644 --- a/src/crypt-aes.c +++ b/src/crypt-aes.c @@ -530,7 +530,7 @@ void vertex_256_keystream_creation(dsd_state * state, char * key_string) 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++) { vtx_key <<= 16; diff --git a/src/crypt-rc4.c b/src/crypt-rc4.c index 6439731..a7ea062 100644 --- a/src/crypt-rc4.c +++ b/src/crypt-rc4.c @@ -91,14 +91,14 @@ void rc4_block_output (int drop, int keylen, int meslen, uint8_t * key, uint8_t //This is now verified to work after changing the drop byte value from 256 to 0. //also, had to change the application to not skip the additional 7 bits like DMRA or P25 does. -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) { UNUSED(opts); - uint8_t key[5]; memset (key, 0, sizeof(key)); - uint8_t kiv[5]; memset (kiv, 0, sizeof(kiv)); - uint8_t mi[5]; memset (mi, 0, sizeof(mi)); - uint8_t ks[135]; memset (ks, 0, sizeof(ks)); + uint8_t key[5]; memset (key, 0, sizeof(key)); + uint8_t kiv[5]; memset (kiv, 0, sizeof(kiv)); + uint8_t mi[5]; memset (mi, 0, sizeof(mi)); + uint8_t ks[2000]; memset (ks, 0, sizeof(ks)); //load key_value into key array key[0] = ((key_value & 0xFF00000000) >> 32UL); @@ -121,17 +121,17 @@ void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long else ks_octets = state->ks_octetR; //NOTE: Drop Byte value is 0 - rc4_block_output(0, 5, 135, key, ks); + rc4_block_output(0, 5, len, key, ks); for (int i = 0; i < 5; i++) kiv[i] = key[i] ^ mi[i]; - for (int i = 0; i < 135; i++) + for (int i = 0; i < len; i++) ks_octets[i] = kiv[i%5] ^ ks[i]; //debug // fprintf (stderr, " KS: "); - // for (int i = 0; i < 135; i++) + // for (int i = 0; i < len; i++) // { // if ((i != 0) && ((i%7) == 0)) // fprintf (stderr, " "); @@ -345,3 +345,1120 @@ void vertex_keystream_setup(dsd_state * state, char * input) END_KS: ; //do nothing } + +//https://patents.google.com/patent/CN106789903B/en +void hytera_ota_keystream_setup(dsd_state * state, char * input) +{ + + uint16_t type = 0; + char * curr; + curr = strtok(input, ":"); + if (curr != NULL) + sscanf (curr, "%hd", &type); + else goto END_KS; + + //type sanity check + if (type != 0 && type != 128) + { + fprintf (stderr, "Hytera OTA Encryption Invalid Key type Specified;"); + goto END_KS; + } + + curr = strtok(NULL, ":"); //should be key in hex + if (curr == NULL) + { + fprintf (stderr, "Hytera OTA Encryption No Key Value Specified;"); + goto END_KS; + } + + if (type == 0) //No Key specified, just check for potential HOTA and DMRA EP + { + fprintf (stderr, "Hytera OTA Encryption Check w/ DMRA EP Late Entry IV Check;\n"); + state->hota_enc_check = 1; + } + else //if (type == 128) //RC4 setup on keystream + { + uint8_t key[50]; + memset(key, 0, sizeof(key)); + + parse_raw_user_string(curr, key); + + // #ifdef DEBUG_HOTA + fprintf(stderr, "Hytera OTA Encryption RC4 Key: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", key[i]); + fprintf (stderr, "\n"); + // #endif + + for (int i = 0; i < 16; i++) + state->hota_rc4_key[i] = key[i]; + + uint8_t ks_bytes[80]; + memset(ks_bytes, 0, sizeof(ks_bytes)); + + //NOTE: Drop Byte value is 0 + rc4_block_output(0, 16, 80, key, ks_bytes); + + #ifdef DEBUG_HOTA + for (int j = 0; j < 5; j++) + { + fprintf(stderr, "Hytera OTA Encryption RC4 KS: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", ks_bytes[i+j*16]); + fprintf (stderr, "\n"); + } + #endif + + for (int i = 0; i < 80; i++) + state->hota_rc4_ks[i] = ks_bytes[i]; + + //configure individual byte and full 96-bit PDU bit final bit shift / rotations + for (int i = 0; i < 12; i++) + state->hota_byte_shifts[i] = ks_bytes[i+16] % 8; + + state->hota_bit_shift = ks_bytes[29]; + state->hota_bit_shift <<= 8; + state->hota_bit_shift |= ks_bytes[28]; + state->hota_bit_shift %= 96; + + #ifdef DEBUG_HOTA + fprintf(stderr, "Hytera OTA Full Bit Shift: %d; Hytera OTA Byte Shifts: ", state->hota_bit_shift); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%d,", state->hota_byte_shifts[i]); + fprintf (stderr, "\n"); + #endif + + state->hota_key_loaded = 1; + state->dmr_is_hota = 1; + } + + END_KS: // + +} + +void rsr_rot(uint8_t * input, int16_t bitlen) +{ + uint8_t bit = input[bitlen-1]; + for (int16_t i = (bitlen-1); i > 0; i--) + input[i] = input[i-1]; + input[0] = bit; +} + +void lsr_rot(uint8_t * input, int16_t bitlen) +{ + uint8_t bit = input[0]; + for (int16_t i = 0; i < (bitlen-1); i++) + input[i] = input[i+1]; + input[(bitlen-1)] = bit; +} + +void hytera_ota_decrypt_bptc_96(dsd_state * state, uint8_t * input, uint8_t type) +{ + + uint8_t bits[96]; + memset(bits, 0, sizeof(bits)); + + uint8_t bytes[12]; + memset(bytes, 0, sizeof(bytes)); + + for (int i = 0; i < 96; i++) + bits[i] = input[i]; + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n\n-----BPTC 96 Bit Decryption-----"); + #endif + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n"); + fprintf(stderr, "HOTA Inp: "); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%02X", convert_bits_into_output(bits+i*8, 8)); + #endif + + //RC4 key type decryption + if (state->hota_key_loaded == 1) + { + + //reverse the final bit rotation with a right shift register + for (int i = 0; i < state->hota_bit_shift; i++) + rsr_rot(bits, 96); + + //reverse the individual bit rotations in each byte with a right shift register + for (int i = 0; i < 12; i++) + { + int shift = state->hota_byte_shifts[i]; + for (int j = 0; j < shift; j++) + rsr_rot(bits+(i*8), 8); + } + + pack_bit_array_into_byte_array(bits, bytes, 12); + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n"); + fprintf(stderr, "HOTA Rot: "); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%02X", bytes[i]); + #endif + + //create a new RC4 keystream derivitive with preconfigured HOTA Keystream + uint8_t key[19]; + memset(key, 0, sizeof(key)); + for (int i = 0; i < 16; i++) + key[i] = state->hota_rc4_key[i]; + + int plen = 9; + int blen = 72; + int klen = 16; + int k = type; + + //VLC or TLC w/ RS encoding + if (type == 1 || type == 2) + { + key[klen] = (uint8_t)convert_bits_into_output(bits+blen, 8); + key[klen++] ^= state->hota_rc4_ks[k++ % 16]; + blen += 8; + key[klen] = (uint8_t)convert_bits_into_output(bits+blen, 8); + key[klen++] ^= state->hota_rc4_ks[k++ % 16]; + blen += 8; + key[klen] = (uint8_t)convert_bits_into_output(bits+blen, 8); + key[klen++] ^= state->hota_rc4_ks[k++ % 16]; + blen += 8; + } + else //CRC16 + { + plen = 10; + blen = 80; + key[klen] = (uint8_t)convert_bits_into_output(bits+blen, 8); + key[klen++] ^= state->hota_rc4_ks[k++ % 16]; + blen += 8; + key[klen] = (uint8_t)convert_bits_into_output(bits+blen, 8); + key[klen++] ^= state->hota_rc4_ks[k++ % 16]; + blen += 8; + } + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n"); + fprintf(stderr, "HOTA KEY: "); + for (int i = 0; i < klen; i++) + fprintf (stderr, "%02X", key[i]); + #endif + + uint8_t ks_bytes[12]; + memset(ks_bytes, 0, sizeof(ks_bytes)); + + //NOTE: Drop Byte value is 0 + rc4_block_output(0, klen, plen, key, ks_bytes); + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n"); + fprintf(stderr, "HOTA RC4: "); + for (int i = 0; i < plen; i++) + fprintf (stderr, "%02X", ks_bytes[i]); + #endif + + //reset the klen pointer to the start of the RS or CRC encoding + klen -= (12 - plen); + + //decrypt final bytes + for (int i = 0; i < plen; i++) + bytes[i] ^= ks_bytes[i]; + + //Add current RS or CRC encoding + for (int i = plen; i < 12; i++) + bytes[i] = key[klen++]; + + // #ifdef DEBUG_HOTA + // fprintf (stderr, "\n"); + // fprintf(stderr, "HOTA Type: %X; PLEN: %d; BLEN: %d; KLEN: %d; K: %d;", type, plen, blen, klen, k); + // #endif + + //unpack the final decrypted bytes back into a bit array + unpack_byte_array_into_bit_array(bytes, input, 12); + + } + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n"); + fprintf(stderr, "HOTA Out: "); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%02X", bytes[i]); + fprintf (stderr, "\n"); + #endif + +} + +static const uint8_t elc_row_map[77] = { + /* R0: (h0 << 3) | (h1 >> 5) */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + + /* R1: ((h1 & 0x1F) << 6) | (h2 >> 2) */ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + + /* R2: ((h2 & 0x03) << 9) | (h3 << 1) | CRC[4] */ + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 72, + + /* R3: (h4 << 3) | ((h5 >> 6) << 1) | CRC[3] */ + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 73, + + /* R4: ((h5 & 0x3F) << 5) | ((h6 >> 4) << 1) | CRC[2] */ + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 74, + + /* R5: ((h6 & 0x0F) << 7) | ((h7 >> 2) << 1) | CRC[1] */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 75, + + /* R6: ((h7 & 0x03) << 9) | (h8 << 1) | CRC[0] */ + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 76 +}; + +void hytera_create_lc_ctx(dsd_state * state, uint8_t * input) +{ + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n-----Voice LC 4 Byte CTX-----"); + #endif + + uint8_t bits[77]; + memset(bits, 0, sizeof(bits)); + + for (int i = 0; i < 72; i++) + bits[i] = input[i] & 1; + + /* Mode 1: left-rotate LC by 1 bit before CRC and rows */ + // if (mode) //never been observed, so disabling this + // lsr_rot(bits, 72); + + /* CRC5 over the 9 bytes */ + uint32_t crc5 = 0; + for (int i = 0; i < 9; i++) + crc5 += convert_bits_into_output(bits + (i * 8), 8); + crc5 %= 31; + + for (int i = 0; i < 5; i++) + bits[72 + i] = (crc5 >> (4 - i)) & 1; + + uint16_t rows[7] = {0}; + for (int i = 0; i < 77; i++) { + rows[i / 11] <<= 1; + rows[i / 11] |= bits[elc_row_map[i]] & 1; + } + + #ifdef DEBUG_HOTA + fprintf (stderr, "\nHOTA ROW: "); + for (int i = 0; i < 7; i++) + fprintf (stderr, "%03X ", rows[i]); + #endif + + uint16_t q0 = rows[3] & 0x7FF; + uint16_t q1 = 0; + for (int i = 0; i < 7; i++) + q1 ^= rows[i]; + q1 &= 0x7FF; + + uint8_t ctx_out[4]; + ctx_out[0] = (uint8_t)(q0 >> 3); + ctx_out[1] = (uint8_t)((q0 & 7) << 5); + ctx_out[2] = (uint8_t)(q1 >> 3); + ctx_out[3] = (uint8_t)((q1 & 7) << 5); + + //load ctx to state + for (int i = 0; i < 4; i++) + state->hota_lc_ctx[state->currentslot][i] = ctx_out[i]; + + //signal ctx is available for embedded lc + state->hota_ctx_ok[state->currentslot] = 1; //disable to test the search + + #ifdef DEBUG_HOTA + fprintf (stderr, "\nHOTA CTX: Q0: %03X; Q1: %03X; CTX: %02X %02X %02X %02X;\n", q0, q1, ctx_out[0], ctx_out[1], ctx_out[2], ctx_out[3]); + #endif +} + +static const uint8_t elc_transpose_map[32] = { + 0, 4, 8, 12, 16, 20, 24, 28, /* → result bits 31..24 */ + 1, 5, 9, 13, 17, 21, 25, 29, /* → result bits 23..16 */ + 2, 6, 10, 14, 18, 22, 26, 30, /* → result bits 15.. 8 */ + 3, 7, 11, 15, 19, 23, 27, 31 /* → result bits 7.. 0 */ +}; + +void hytera_ota_decrypt_emb_lc(dsd_state * state, uint8_t input[8][16]) +{ + + if (state->hota_ctx_ok[state->currentslot] == 0) + return; + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n-----EMB LC and FEC Decryption-----\n"); + #endif + + uint8_t bits[128]; + memset(bits, 0, sizeof(bits)); + + uint8_t bytes[16]; + memset(bytes, 0, sizeof(bytes)); + + int k = 0; + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA Inp: "); + for (int i = 0; i < 8; i++) + fprintf (stderr, "%04X", (uint16_t)convert_bits_into_output(input[i], 16)); + fprintf (stderr, "\n"); + #endif + + //OTA load as linear bits + for (int i = 0; i < 16; i++) + { + for (int j = 0; j < 8; j++) + bits[k++] = input[j][i]; + } + + pack_bit_array_into_byte_array(bits, bytes, 16); + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA Col: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", bytes[i]); + fprintf (stderr, "\n"); + #endif + + //RC4 things + uint8_t key[20]; + memset(key, 0, sizeof(key)); + + uint8_t ks_bytes[16]; + memset(ks_bytes, 0, sizeof(ks_bytes)); + + k = 0; + for (int i = 0; i < 16; i++) + key[k++] = state->hota_rc4_key[i]; + + for (int i = 0; i < 4; i++) + key[k++] = state->hota_lc_ctx[state->currentslot][i]; + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA Key: "); + for (int i = 0; i < 20; i++) + fprintf (stderr, "%02X", key[i]); + fprintf (stderr, "\n"); + #endif + + //NOTE: Drop Byte value is 0 + rc4_block_output(0, 20, 16, key, ks_bytes); + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA RC4: "); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%02X", ks_bytes[i]); + fprintf (stderr, "\n"); + #endif + + //Nibble swap from state->hota_rc4_ks + ks_bytes[1] &= 0xF0; + ks_bytes[1] |= state->hota_rc4_ks[30] & 0xF; + + ks_bytes[3] &= 0xF0; + ks_bytes[3] |= state->hota_rc4_ks[31] & 0xF; + + ks_bytes[5] &= 0xF0; + ks_bytes[5] |= state->hota_rc4_ks[32] & 0xF; + + ks_bytes[7] &= 0xF0; + ks_bytes[7] |= state->hota_rc4_ks[33] & 0xF; + + ks_bytes[9] &= 0xF0; + ks_bytes[9] |= state->hota_rc4_ks[34] & 0xF; + + ks_bytes[11] &= 0xF0; + ks_bytes[11] |= state->hota_rc4_ks[35] & 0xF; + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA Nib: "); + for (int i = 0; i < 6; i++) + fprintf (stderr, " %X", state->hota_rc4_ks[i+30] & 0xF); + fprintf (stderr, "\n"); + #endif + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA RC4: "); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%02X", ks_bytes[i]); + fprintf (stderr, "\n"); + #endif + + //M0, M1, M2 values + uint8_t ks_bits[128]; + memset(ks_bits, 0, sizeof(ks_bits)); + unpack_byte_array_into_bit_array(ks_bytes, ks_bits, 16); + + uint8_t int_bits[128]; + memset(int_bits, 0, sizeof(int_bits)); + + k = 0; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 32; j++) + int_bits[k++] = ks_bits[elc_transpose_map[j]+(i*32)]; + } + + uint8_t int_bytes[16]; + memset(int_bytes, 0, sizeof(int_bytes)); + + pack_bit_array_into_byte_array(int_bits, int_bytes, 16); + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA Int: "); + for (int i = 0; i < 12; i++) + fprintf (stderr, "%02X", int_bytes[i]); + fprintf (stderr, "\n"); + #endif + + //reorder the int_bytes + memset(ks_bytes, 0, sizeof(ks_bytes)); + + k = 0; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i]; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i+4]; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i+4]; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i+8]; + + for (int i = 0; i < 16; i++) + bytes[i] ^= ks_bytes[i]; + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA KS2: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", ks_bytes[i]); + fprintf (stderr, "\n"); + #endif + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA Out: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", bytes[i]); + fprintf (stderr, "\n\n"); + #endif + + unpack_byte_array_into_bit_array(bytes, bits, 16); + + k = 0; + + //OTA reload from linear bits to 2d input array + for (int i = 0; i < 16; i++) + { + for (int j = 0; j < 8; j++) + input[j][i] = bits[k++]; + } + +} + +//This is a modified decrypt but to brute force an unknown 22-bit ctx value +//This should not be run on live systems, but useful for replay or debug +//This takes around 25 seconds on a full search and failure on Ryzen 5 2600 +void hytera_ota_search_emb_lc(dsd_state * state, uint8_t input[8][16]) +{ + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n-----EMB LC and FEC CTX Search-----\n"); + #endif + + for (uint32_t ctx = 0; ctx < 0x3FFFFF; ctx++) + { + + uint8_t bits[128]; + memset(bits, 0, sizeof(bits)); + + uint8_t bytes[16]; + memset(bytes, 0, sizeof(bytes)); + + int k = 0; + + //OTA load as linear bits + for (int i = 0; i < 16; i++) + { + for (int j = 0; j < 8; j++) + bits[k++] = input[j][i]; + } + + pack_bit_array_into_byte_array(bits, bytes, 16); + + uint16_t q0 = 0, q1 = 0; + q0 = (ctx >> 11) & 0x7FF; + q1 = (ctx >> 0) & 0x7FF; + + uint8_t ctx_out[4]; + memset(ctx_out, 0, sizeof(ctx_out)); + + ctx_out[0] = (uint8_t)(q0 >> 3); + ctx_out[1] = (uint8_t)((q0 & 7) << 5); + ctx_out[2] = (uint8_t)(q1 >> 3); + ctx_out[3] = (uint8_t)((q1 & 7) << 5); + + //RC4 things + uint8_t key[20]; + memset(key, 0, sizeof(key)); + + uint8_t ks_bytes[16]; + memset(ks_bytes, 0, sizeof(ks_bytes)); + + k = 0; + for (int i = 0; i < 16; i++) + key[k++] = state->hota_rc4_key[i]; + + for (int i = 0; i < 4; i++) + key[k++] = ctx_out[i]; + + //NOTE: Drop Byte value is 0 + rc4_block_output(0, 20, 16, key, ks_bytes); + + //Nibble swap from state->hota_rc4_ks + ks_bytes[1] &= 0xF0; + ks_bytes[1] |= state->hota_rc4_ks[30] & 0xF; + + ks_bytes[3] &= 0xF0; + ks_bytes[3] |= state->hota_rc4_ks[31] & 0xF; + + ks_bytes[5] &= 0xF0; + ks_bytes[5] |= state->hota_rc4_ks[32] & 0xF; + + ks_bytes[7] &= 0xF0; + ks_bytes[7] |= state->hota_rc4_ks[33] & 0xF; + + ks_bytes[9] &= 0xF0; + ks_bytes[9] |= state->hota_rc4_ks[34] & 0xF; + + ks_bytes[11] &= 0xF0; + ks_bytes[11] |= state->hota_rc4_ks[35] & 0xF; + + //M0, M1, M2 values + uint8_t ks_bits[128]; + memset(ks_bits, 0, sizeof(ks_bits)); + unpack_byte_array_into_bit_array(ks_bytes, ks_bits, 16); + + uint8_t int_bits[128]; + memset(int_bits, 0, sizeof(int_bits)); + + k = 0; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 32; j++) + int_bits[k++] = ks_bits[elc_transpose_map[j]+(i*32)]; + } + + uint8_t int_bytes[16]; + memset(int_bytes, 0, sizeof(int_bytes)); + + pack_bit_array_into_byte_array(int_bits, int_bytes, 16); + + //reorder the int_bytes + memset(ks_bytes, 0, sizeof(ks_bytes)); + + k = 0; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i]; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i+4]; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i+4]; + for (int i = 0; i < 4; i++) + ks_bytes[k++] = int_bytes[i+8]; + + for (int i = 0; i < 16; i++) + bytes[i] ^= ks_bytes[i]; + + unpack_byte_array_into_bit_array(bytes, bits, 16); + + //FEC test on results, break and set ctx if good and unique (only one good?) + uint8_t matrix[8][16]; + memset(matrix, 0, sizeof(matrix)); + + //OTA reload from linear bits to 2d input array + k = 0; + for (int i = 0; i < 16; i++) + { + for (int j = 0; j < 8; j++) + matrix[j][i] = bits[k++]; + } + + //This will not correct, but reports all errors (hamming corrections and parity) + uint32_t errors = BPTC_128x77_Check_Errors(matrix); + + if (errors == 0) + { + + //Extract + CRC5 to validate + uint8_t lc77[77]; + if (BPTC_128x77_Extract_Data(matrix, lc77) == 0 && + ComputeCrc5Bit(lc77) == ConvertBitIntoBytes(&lc77[72], 5)) + { + + #ifdef DEBUG_HOTA + fprintf (stderr, "CTX: %06X; Q0: %03X; Q1: %03X;\n", ctx, q0, q1); + fprintf (stderr, "ERR: %d; CRC EXT: %02X; CRC CMP: %02X\n", errors, ComputeCrc5Bit(lc77), ConvertBitIntoBytes(&lc77[72], 5)); + fprintf(stderr, "HOTA Out: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", bytes[i]); + fprintf (stderr, "\n\n"); + #endif + + //set missing CTX here, set flag for okay ctx, and return + for (int i = 0; i < 4; i++) + state->hota_lc_ctx[state->currentslot][i] = ctx_out[i]; + state->hota_ctx_ok[state->currentslot] = 1; + return; + } + + } + + //get out of brute force loop early on exit signal + if (exitflag) + break; + + } + +} + +void hytera_ota_unit_testing(dsd_state * state) +{ + char keystr[100]; + memset(keystr, 0, sizeof(keystr)); + sprintf (keystr, "%s", "2:17bfe59b29a06136fb7d3811fd1a4904"); + hytera_ota_keystream_setup(state, keystr); + + char string[30]; + memset(string, 0, sizeof(string)); + + uint8_t bytes[12]; + uint8_t bits[96]; + + //PI header + memset(string, 0, sizeof(string)); + sprintf(string, "%s", "2ca5f7b049c350664cf09e4e"); + memset(bytes, 0, sizeof(bytes)); + memset(bits, 0, sizeof(bits)); + parse_raw_user_string(string, bytes); + unpack_byte_array_into_bit_array(bytes, bits, 12); + hytera_ota_decrypt_bptc_96(state, bits, 0); + fprintf (stderr, "\n"); + + //VLC + memset(string, 0, sizeof(string)); + sprintf(string, "%s", "de4998491fe4da822d5d5568"); + memset(bytes, 0, sizeof(bytes)); + memset(bits, 0, sizeof(bits)); + parse_raw_user_string(string, bytes); + unpack_byte_array_into_bit_array(bytes, bits, 12); + hytera_ota_decrypt_bptc_96(state, bits, 1); + fprintf (stderr, "\n"); + + //TLC + memset(string, 0, sizeof(string)); + sprintf(string, "%s", "012f658c3f2a70a8d4766a95"); + memset(bytes, 0, sizeof(bytes)); + memset(bits, 0, sizeof(bits)); + parse_raw_user_string(string, bytes); + unpack_byte_array_into_bit_array(bytes, bits, 12); + hytera_ota_decrypt_bptc_96(state, bits, 2); + fprintf (stderr, "\n"); + + //CSBK + memset(string, 0, sizeof(string)); + sprintf(string, "%s", "1053505ed9b4ff091b36a5c3"); + memset(bytes, 0, sizeof(bytes)); + memset(bits, 0, sizeof(bits)); + parse_raw_user_string(string, bytes); + unpack_byte_array_into_bit_array(bytes, bits, 12); + hytera_ota_decrypt_bptc_96(state, bits, 3); + fprintf (stderr, "\n"); + + //data header + memset(string, 0, sizeof(string)); + sprintf(string, "%s", "cba5da41f9fb252ca859ff89"); + memset(bytes, 0, sizeof(bytes)); + memset(bits, 0, sizeof(bits)); + parse_raw_user_string(string, bytes); + unpack_byte_array_into_bit_array(bytes, bits, 12); + hytera_ota_decrypt_bptc_96(state, bits, 6); + fprintf (stderr, "\n"); + + //single burst encoding + memset(bits, 0, sizeof(bits)); + uint16_t sb_hex = 0x14; //key id 0x14 like in sample + sb_hex <<= 3; + sb_hex |= 0x01; //alg 0x01 (RC4) + + //05030A03 is key id 1, alg 1 (009) + //HOTA SB INT: 05030A03 + //HOTA SB DEI: 01310131 + //SB: 00000001001 - 009; + //Slot 2 DMR LE SB ALG ID: 21; KEY ID: 01; RC4; + + //debug + // sb_hex = 0x009; + + //load into bit array + for (int i = 0; i < 11; i++) + bits[i] = (sb_hex >> (10-i)) & 1; + + //hamming 16_11_4 encode + uint8_t encoded[32]; + memset(encoded, 0, sizeof(encoded)); + Hamming_16_11_4_encode(bits, encoded); + + //Parity Bit Row (even) --> just duplicate the first 16 + for (int i = 0; i < 16; i++) + encoded[i+16] = encoded[i]; + + //NOTE: For RC, just invert each bit instead + // for (int i = 0; i < 16; i++) + // encoded[i+16] = encoded[i] ^ 1; + + //placement and interleaving + uint8_t interleave[32]; + memset(interleave, 0, sizeof(interleave)); + + const uint8_t sbrc_int[32] = + { + 0,24,1,25,2,26,3,27,4,28,5,29,6,30,7,31,8, + 16,9,17,10,18,11,19,12,20,13,21,14,22,15,23 + }; + + for (int i = 0; i < 32; i++) + interleave[i] = encoded[sbrc_int[i]]; + + fprintf (stderr, "\n"); + fprintf (stderr, "EMB RC / SB HEX: %03X;", sb_hex); + fprintf (stderr, "\n"); + fprintf (stderr, "Hamming Encoded: %04X", convert_bits_into_output(encoded, 16)); + fprintf (stderr, "\n"); + fprintf (stderr, "Even PB Encoded: %08X", convert_bits_into_output(encoded, 32)); + fprintf (stderr, "\n"); + fprintf (stderr, "CAI Interleaved: %08X", convert_bits_into_output(interleave, 32)); + + exitflag = 1; + +} + +//Apply KS to the Single Burst or Reverse Channel using indexed values. +void hytera_ota_decrypt_sb_rc(dsd_state * state, uint8_t * input) +{ + + if (state->hota_key_loaded == 0) + return; + else if (state->hota_sbrc_idx1[state->currentslot] == -1) + return; + else if (state->hota_sbrc_idx2[state->currentslot] == -1) + return; + + uint8_t bits[32]; + memset(bits, 0, sizeof(bits)); + + //check for empty field (NULL message), return if empty + if (memcmp(bits, input, 32) == 0) + return; + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n\n-----SB_RC and FEC Decryption-----"); + #endif + + for (int i = 0; i < 32; i++) + bits[i] = input[i] & 1; + + uint8_t bytes[4]; + pack_bit_array_into_byte_array(bits, bytes, 4); + + #ifdef DEBUG_HOTA + fprintf(stderr, "\n"); + fprintf(stderr, "HOTA SB Inp: "); + for (int i = 0; i < 4; i++) + fprintf(stderr, "%02X", bytes[i]); + fprintf(stderr, "\n"); + #endif + + static const uint8_t sbrc_int[32] = { + 0,24,1,25,2,26,3,27,4,28,5,29,6,30,7,31,8, + 16,9,17,10,18,11,19,12,20,13,21,14,22,15,23 + }; + + uint8_t dei[32]; + for (int i = 0; i < 32; i++) + dei[sbrc_int[i]] = bits[i]; + + for (int i = 0; i < 32; i++) + bits[i] = dei[i]; + + pack_bit_array_into_byte_array(bits, bytes, 4); + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA SB Dei: "); + for (int i = 0; i < 4; i++) + fprintf(stderr, "%02X", bytes[i]); + fprintf(stderr, "\n"); + #endif + + //idx values for KS based on calculation or prior search + int idx1 = state->hota_sbrc_idx1[state->currentslot]; + int idx2 = state->hota_sbrc_idx2[state->currentslot]; + + //The index values are always hardset according to test w/ multiple keys + uint16_t S = (uint16_t)state->hota_rc4_ks[idx1+0] | ((uint16_t)state->hota_rc4_ks[idx1+1] << 8); + uint16_t Q = ((uint16_t)state->hota_rc4_ks[idx2+0] << 8) | (uint16_t)state->hota_rc4_ks[idx2+1]; + + uint16_t U = ((uint16_t)bytes[0] << 8) | bytes[1]; + uint16_t V = ((uint16_t)bytes[2] << 8) | bytes[3]; + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA SB UV: U=%04X V=%04X\n", U, V); + #endif + + //apply keystream + V ^= S; + U ^= Q; + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA SB Dec: U=%04X V=%04X idx1=%u idx2=%u S=%04X Q=%04X\n", U, V, idx1, idx2, S, Q); + #endif + + //swap endianness of U and V for unpacking + bytes[0] = (uint8_t)(U >> 8); + bytes[1] = (uint8_t)(U & 0xFF); + bytes[2] = (uint8_t)(V >> 8); + bytes[3] = (uint8_t)(V & 0xFF); + + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA SB Dec: "); + for (int i = 0; i < 4; i++) + fprintf(stderr, "%02X", bytes[i]); + fprintf(stderr, "\n"); + #endif + + unpack_byte_array_into_bit_array(bytes, bits, 4); + for (int i = 0; i < 32; i++) + input[i] = bits[sbrc_int[i]]; + + pack_bit_array_into_byte_array(input, bytes, 4); + #ifdef DEBUG_HOTA + fprintf(stderr, "HOTA SB Out: "); + for (int i = 0; i < 4; i++) + fprintf(stderr, "%02X", bytes[i]); + fprintf(stderr, "\n"); + #endif +} + +//UPDATE: So, does appear that this field changes depending on other factors +//not key related directly, but could be CTX related, or RID or similar, +//code has been updated appropriately to continue the search on this +//its possible that idx1 is still always 36, idx2 is variable +void hytera_ota_search_sb_rc(dsd_state * state, uint8_t * input, int ptype) +{ + + if (state->hota_key_loaded == 0) + return; + else if (ptype > 1) + return; + + uint8_t bits[32]; + memset (bits, 0, sizeof(bits)); + + //check for empty field (NULL message), return if empty + if (memcmp(bits, input, 32) == 0) + return; + + #ifdef DEBUG_HOTA + fprintf (stderr, "\n\n-----SB_RC KS Index Search-----"); + #endif + + static const uint8_t sbrc_int[32] = { + 0,24,1,25,2,26,3,27,4,28,5,29,6,30,7,31,8, + 16,9,17,10,18,11,19,12,20,13,21,14,22,15,23 + }; + + for (int i = 0; i < 32; i++) + bits[sbrc_int[i]] = input[i]; + + uint8_t bytes[4]; + memset(bytes, 0, sizeof(bytes)); + + pack_bit_array_into_byte_array(bits, bytes, 4); + + uint16_t S = 0, Q = 0, U = 0, V = 0, Y = 0, Z = 0; + + uint8_t * K = &state->hota_rc4_ks[0]; + + U = ((uint16_t)bytes[0] << 8) | bytes[1]; + V = ((uint16_t)bytes[2] << 8) | bytes[3]; + + #ifdef DEBUG_HOTA + fprintf (stderr, "\nSB_RC ENC U: %04X; ENC V: %04X; PPI: %d;", U, V, ptype); + #endif + + // for (int i = 0; i < 80; i++) //may can end at 40, or remove loop and hard set to 36 + { + + int i = 36; //hardset i for idx1 that seems to be a constant + + //Calculate Clear V from S stream bytes + S = (K[(i+0) % 80] << 0) | (K[(i+1) % 80] << 8); + Y = V ^ S; + + //invert parity row bits if needed + if (ptype) + Y = ~Y; + + for (int j = 0; j < 80; j++) //can be in range of 0 to 80, verified + { + + //calculate Clear U from Q stream bytes + Q = (K[(j+0) % 80] << 8) | (K[(j+1) % 80] << 0); + Z = U ^ Q; + + //Y and Z match, proceed + if (Y == Z) + { + //hamming encode on the 11-bit data portion of Clear U (Z) to see if it matches 5 lsb + unsigned char hamming[16]; memset(hamming, 0, sizeof(hamming)); + unsigned char hammchk[16]; memset(hammchk, 0, sizeof(hammchk)); + for (int h = 0; h < 16; h++) + hamming[h] = (Z >> (15 - h)) & 1; + Hamming_16_11_4_encode(hamming, hammchk); + + //hamming result is positive, successful search + if (memcmp(hamming, hammchk, 16) == 0) + { + #ifdef DEBUG_HOTA + fprintf (stderr, "\nSuccess: IDX1: %d; IDX2: %d; ", i, j); + fprintf (stderr, "S: %04X; Q: %04X; CLR U: %04X; CLR V: %04X;", S, Q, Z, Y); + // fprintf (stderr, " HE: %04X; HC: %04X;", (uint16_t)convert_bits_into_output(hamming, 16), (uint16_t)convert_bits_into_output(hammchk, 16)); + #endif + state->hota_sbrc_idx1[state->currentslot] = i; + state->hota_sbrc_idx2[state->currentslot] = j; + return; + } + } + } + } + +} + +uint8_t hytera_ep_data_decrypt(dsd_opts * opts, dsd_state * state, uint8_t * input, int len) +{ + uint8_t slot = state->currentslot; + if (slot == 0 && state->payload_algid != 0xD0) + return 0; + else if (slot == 1 && state->payload_algidR != 0xD0) + return 0; + + //TODO: Attempt Load by TG value as well + //TODO: Hytera EP Data Header does have a Key ID, + //attempt loading by either TG or Key ID as well + + unsigned long long int R = 0; + if (slot == 0) + R = state->R; + else R = state->RR; + + if (R == 0) + return 0; + + unsigned long long int mi = 0; + if (slot == 0) + mi = state->payload_mi; + else mi = state->payload_miR; + + if (mi == 0) + return 0; + + //TODO: 2000 -> expected size of decryption + hytera_enhanced_rc4_setup(opts, state, R, mi, 2000); + + uint8_t ks_bytes[2000]; + memset(ks_bytes, 0, sizeof(ks_bytes)); + + if (slot == 0) + memcpy(ks_bytes, state->ks_octetL, 2000); + else memcpy(ks_bytes, state->ks_octetR, 2000); + + //find current idx for keystream application + int bp_idx = (state->data_block_counter[slot] - 1) * len; + + //apply keystream + for (int i = 0; i < len; i++) + input[i] ^= ks_bytes[bp_idx++]; + + //return this is decrypted + return 1; + +} + +uint8_t hytera_bp_data_decrypt(dsd_state * state, uint8_t * input, int len) +{ + + uint8_t slot = state->currentslot; + if (slot == 0 && state->payload_algid != 0x68) + return 0; + else if (slot == 1 && state->payload_algidR != 0x68) + return 0; + + //load Hytera BP Key + uint8_t key_loaded = 0; + uint8_t key[32]; memset(key, 0, sizeof(key)); + uint8_t empt[32]; memset(empt, 0, sizeof(empt)); + + //TODO: Attempt Load by TG value as well + //TODO: Hytera BP Data Header does have a Key ID, + //attempt loading by either TG or Key ID as well + + for (int i = 0; i < 8; i++) + { + key[i+0] = (state->K1) >> (56-(i*8)) & 0xFF; + key[i+8] = (state->K2) >> (56-(i*8)) & 0xFF; + key[i+16] = (state->K3) >> (56-(i*8)) & 0xFF; + key[i+24] = (state->K4) >> (56-(i*8)) & 0xFF; + } + + //if key is loaded with a key, then flag on the key loaded variable + if (memcmp(key, empt, sizeof(key)) != 0) key_loaded = 1; + + if (key_loaded == 0) + return 0; + + uint8_t key_bytes[64]; + memset (key_bytes, 0, sizeof(key_bytes)); + + //Find len on loaded Hytera BP key w/ memcmp on key and load into key_bytes + int key_len = 32; + + //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(empt, key+16, 8) != 0) || (memcmp(empt, key+24, 8) != 0)) + { + memcpy(key_bytes, key, 32); + key_len = 32; + } + //test for 32 char (16 byte) key + else if ((memcmp(empt, key+8, 8) != 0)) + { + memcpy(key_bytes, key, 16); + key_len = 16; + } + //this is a 10 char (5 byte) key w/ offset + else + { + memcpy(key_bytes, key+3, 5); + key_len = 5; + } + + //find current idx for keystream application + int bp_idx = (state->data_block_counter[slot] - 1) * len; + + //apply keystream + for (int i = 0; i < len; i++) + input[i] ^= key_bytes[bp_idx++ % key_len]; + + //return this is decrypted + return 1; + +} diff --git a/src/dmr_block.c b/src/dmr_block.c index 9dab74a..e15c86f 100644 --- a/src/dmr_block.c +++ b/src/dmr_block.c @@ -1157,135 +1157,16 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte decrypted_pdu = 1; } - else if (alg == 0x68 && akl == 1) //Hytera BP + else if (alg == 0x68) //Hytera BP { - - //Find len on loaded Hytera BP key w/ memcmp on kaes and load into ob - 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); - + //just passing through to see if a key was loaded and the blocks decrypted + decrypted_pdu = hytera_bp_data_decrypt(state, empt, 1); } - 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 - //also, will need to make more ks with a len option in function - //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); - + //just passing through to see if a key was loaded and the blocks decrypted + decrypted_pdu = hytera_ep_data_decrypt(opts, state, empt, 1); } 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->dmr_lrrp_gps[0], "%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; } \ No newline at end of file diff --git a/src/dmr_bs.c b/src/dmr_bs.c index ce26c27..d6229c4 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -462,6 +462,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state) 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 if (state->payload_algid == 0x02) hytera_enhanced_alg_refresh(state); @@ -475,6 +481,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state) 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 if (state->payload_algidR == 0x02) hytera_enhanced_alg_refresh(state); diff --git a/src/dmr_dburst.c b/src/dmr_dburst.c index de2e8b1..8af236c 100644 --- a/src/dmr_dburst.c +++ b/src/dmr_dburst.c @@ -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_bits, 0, sizeof (DMR_PDU_bits)); + uint8_t hota_enc = 0; uint8_t is_ras = 0; uint8_t bptc_res_bits[3]; 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){ case 0x00: //PI + hota_enc = 1; is_bptc = 1; crclen = 16; 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 "); break; case 0x01: //VLC + hota_enc = 1; is_bptc = 1; is_lc = 1; 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 "); break; case 0x02: //TLC + hota_enc = 1; is_bptc = 1; is_lc = 1; 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 "); break; case 0x03: //CSBK + hota_enc = 1; is_bptc = 1; crclen = 16; 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"); break; case 0x04: //MBC Header + hota_enc = 1; is_bptc = 1; crclen = 16; 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"); break; case 0x06: //Data Header + hota_enc = 1; is_bptc = 1; crclen = 16; crcmask = 0xCCCC; @@ -176,6 +183,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196 } break; case 0x0B: //Unified Single Block Data USBD + hota_enc = 1; is_bptc = 1; crclen = 16; 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) case 0xEB: //Embedded Signalling + hota_enc = 1; crclen = 5; is_emb = 1; 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]); #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 */ 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 } 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) @@ -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(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 */ - 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 */ 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)); 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 //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; 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) if (state->data_conf_data[slot] == 0) CRCCorrect = 1; diff --git a/src/dmr_flco.c b/src/dmr_flco.c index 5bc5471..8e42149 100644 --- a/src/dmr_flco.c +++ b/src/dmr_flco.c @@ -76,10 +76,65 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C //Kirisun if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40 { - //disable late entry for DMRA, Flag 3 if encrypted, 0 if not - if (so & 0x40) - opts->dmr_le = 3; - else opts->dmr_le = 0; + //disable late entry for DMRA, Flag 3 if encrypted, 0 if not + if (so & 0x40) + opts->dmr_le = 3; + 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 @@ -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->event_history_s[0].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA"); 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) { @@ -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->event_history_s[1].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA"); 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; } } diff --git a/src/dmr_le.c b/src/dmr_le.c index 8427751..2fbe80a 100644 --- a/src/dmr_le.c +++ b/src/dmr_le.c @@ -8,6 +8,9 @@ #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 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 (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 (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 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 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 @@ -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) 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 for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3]; diff --git a/src/dsd_file.c b/src/dsd_file.c index 27a045d..509895f 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -877,6 +877,76 @@ void unpack_ambe (uint8_t * input, char * ambe) 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 uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len) { diff --git a/src/dsd_gps.c b/src/dsd_gps.c index 0f13e17..1335c64 100644 --- a/src/dsd_gps.c +++ b/src/dsd_gps.c @@ -528,7 +528,7 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]) if (slot == 1) src = state->lasttgR; //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]); //save to LRRP report for mapping/logging diff --git a/src/dsd_main.c b/src/dsd_main.c index f5d2b1a..e361b01 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -585,6 +585,14 @@ //we do reset the counter, but not the static_ks_bits 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 @@ -1245,6 +1253,21 @@ memset (state->ras_permutation_order, 0, sizeof(state->ras_permutation_order)); state->ras_effective_key = 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_sub, "%s", ""); @@ -1561,6 +1584,10 @@ printf (" -H C:128:736B9A9C5645288B243AD5CB8701EF8A' \n"); printf (" -H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8' \n"); printf ("\n"); + printf (" -H 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 Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n"); printf (" \n"); printf (" -1 Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n"); @@ -2296,11 +2323,16 @@ break; case 'H': - //check for caltta, if not, then use older loader + //check for caltta bp key load if (optarg[0] == 'C' && optarg[1] == ':') { 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 { strncpy(opts.szNumbers, optarg, 1023); @@ -2309,7 +2341,12 @@ state.K2 = strtoull (pEnd, &pEnd, 16); state.K3 = 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_encR = 0; if (state.K1 == 0 && state.K2 == 0 && state.K3 == 0 && state.K4 == 0) diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index d65cb9e..50e1634 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -813,7 +813,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a if(state->payload_algid == 0x02) { 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) { @@ -1313,7 +1313,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a if(state->payload_algidR == 0x02) { 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) { diff --git a/src/rs-12-9.c b/src/rs-12-9.c index 4ccd134..1d8edb2 100644 --- a/src/rs-12-9.c +++ b/src/rs-12-9.c @@ -325,9 +325,6 @@ void rs_12_9_encode(uint8_t * input) //init cw memset(cw.data, 0, 12*sizeof(uint8_t)); - //init cs - memset(cs->bytes, 0, 3*sizeof(uint8_t)); - //Copy 9 bytes of data input memcpy(cw.data, input, 9);