From 8f092e293f6e284be08d464360d7cf2ce5f3f49c Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Fri, 15 Aug 2025 12:21:27 -0400 Subject: [PATCH] DMR TYT BP16 Encryption Mode WIP; #302 Code is not working as-is, committed for anonymous submitter to have access to certain items in code; --- include/dsd.h | 8 +++ src/crypt-tyt.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ src/dmr_bs.c | 38 +++++++++++++ src/dmr_ms.c | 34 ++++++++++++ src/dsd_main.c | 31 ++++++----- src/dsd_mbe.c | 93 ------------------------------- 6 files changed, 240 insertions(+), 106 deletions(-) create mode 100644 src/crypt-tyt.c diff --git a/include/dsd.h b/include/dsd.h index f5f3f6e..98ca932 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -988,6 +988,9 @@ typedef struct //tyt_ap=1 active int tyt_ap; + int tyt_bp; + int tyt_ep; + } dsd_state; /* @@ -1157,6 +1160,8 @@ int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); void keyring(dsd_opts * opts, dsd_state * state); void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state); +void ambe2_codeword_print_f (dsd_opts * opts, char ambe_fr[4][24]); +void ambe2_codeword_print_b (dsd_opts * opts, char ambe_fr[4][24]); void openMbeInFile (dsd_opts * opts, dsd_state * state); void closeMbeOutFile (dsd_opts * opts, dsd_state * state); void closeMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2 @@ -1607,6 +1612,9 @@ void aes_cfb_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, void aes_ctr_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type); void aes_ctr_bitwise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type); +//Tytera Encryption Modes +int tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int idx, int fnum); + //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); unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len); diff --git a/src/crypt-tyt.c b/src/crypt-tyt.c new file mode 100644 index 0000000..d8867fe --- /dev/null +++ b/src/crypt-tyt.c @@ -0,0 +1,142 @@ +#include "dsd.h" + +//de-interleaved code words for AMBE+2 +void ambe2_codeword_print_b (dsd_opts * opts, char ambe_fr[4][24]) +{ + uint8_t fr_reverse[4][24]; memset(fr_reverse, 0, sizeof(fr_reverse)); + for (int i = 0; i < 24; i++) + fr_reverse[0][i] = ambe_fr[0][23-i]; + for (int i = 0; i < 23; i++) + fr_reverse[1][i] = ambe_fr[1][22-i]; + for (int i = 0; i < 11; i++) + fr_reverse[2][i] = ambe_fr[2][10-i]; + for (int i = 0; i < 14; i++) + fr_reverse[3][i] = ambe_fr[3][13-i]; + + uint32_t v0 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[0], 24); //24 + uint32_t v1 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[1], 23); //23 + uint32_t v2 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[2], 11); //11 + uint32_t v3 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[3], 14); //14 + + uint32_t c0 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[0], 12); + uint32_t c1 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[1], 12); + + //72 bit version + unsigned long long int hex1 = ((unsigned long long int)v0 << 40ULL) + ((unsigned long long int)v1 << 17ULL) + ((unsigned long long int)v2 << 6ULL) + (v3 >> 8); + unsigned long long int hex2 = v3 & 0xFF; + + //49 bit version prior to golay correction and c1 demodulation pN + unsigned long long int hex49 = ((unsigned long long int)c0 << 37ULL) + ((unsigned long long int)c1 << 25ULL) + ((unsigned long long int)v2 << 14ULL) + v3; + + UNUSED(opts); + + if (opts->payload == 1) + { + fprintf (stderr, " AMBE HEX(72): %016llX%02llX \n", hex1, hex2); + fprintf (stderr, " AMBE HEX(49): %014llX\n", hex49 << 7); + } + +} + +//de-interleaved code words for AMBE+2 +void ambe2_codeword_print_f (dsd_opts * opts, char ambe_fr[4][24]) +{ + uint32_t v0 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[0], 24); //24 + uint32_t v1 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[1], 23); //23 + uint32_t v2 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[2], 11); //11 + uint32_t v3 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[3], 14); //14 + + // if (opts->payload == 1) + // fprintf (stderr, " AMBE V0: %06X; V1: %06X; V2: %03X; V3: %04X; \n", v0, v1, v2, v3); + + unsigned long long int hex1 = ((unsigned long long int)v0 << 40ULL) + ((unsigned long long int)v1 << 17ULL) + ((unsigned long long int)v2 << 6ULL) + (v3 >> 8); + unsigned long long int hex2 = v3 & 0xFF; + + if (opts->payload == 1) + fprintf (stderr, " AMBE HEX(72): %016llX%02llX \n", hex1, hex2); + +} + +//test application of keystream to codewords instead of ambe_d (tytera / retevis, etc) +int tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int idx, int fnum) +{ + uint8_t ks_bytes[28]; memset(ks_bytes, 0, sizeof(ks_bytes)); + uint8_t ks[224]; memset(ks, 0, sizeof(ks)); + + UNUSED(fnum); + + ks_bytes[0] = (state->H >> 8) & 0xFF; + ks_bytes[1] = (state->H >> 0) & 0xFF; + + //copy same bytes into rest of byte array + for (int16_t i = 2; i < 28; i++) + ks_bytes[i] = ks_bytes[i%2]; + + //debug ks_bytes + // fprintf (stderr, " KB: "); + // for (int16_t i = 0; i < 28; i++) + // fprintf (stderr, "%02X ", ks_bytes[i]); + // fprintf (stderr, "\n"); + + //convert byte array into a bit array + unpack_byte_array_into_bit_array(ks_bytes, ks, 28); + + //debug ks + // fprintf (stderr, " KS: "); + // for (int16_t i = 0; i < 28; i++) + // fprintf (stderr, "%02X ", (uint8_t)convert_bits_into_output(ks+(i*8), 8)); + // fprintf (stderr, "\n"); + + //debug to test application to ambe_fr result + // memset(ambe_fr, 0, 4*24*sizeof(char)); + + if (fnum == 0) + idx = 0; + else idx = 8; + + //straight? + for (int16_t i = 0; i < 24; i++) + ambe_fr[0][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + for (int16_t i = 0; i < 23; i++) + ambe_fr[1][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + for (int16_t i = 0; i < 11; i++) + ambe_fr[2][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + for (int16_t i = 0; i < 14; i++) + ambe_fr[3][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + //backwards? + // for (int16_t i = 13; i >= 0; i--) + // ambe_fr[3][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + // for (int16_t i = 10; i >= 0; i--) + // ambe_fr[2][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + // for (int16_t i = 22; i >= 0; i--) + // ambe_fr[1][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + // for (int16_t i = 23; i >= 0; i--) + // ambe_fr[0][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + //forwards? + // for (int16_t i = 23; i >= 0; i--) + // ambe_fr[0][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + // for (int16_t i = 22; i >= 0; i--) + // ambe_fr[1][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + // for (int16_t i = 10; i >= 0; i--) + // ambe_fr[2][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + // for (int16_t i = 13; i >= 0; i--) + // ambe_fr[3][i] ^= ks[((idx++)%216)] ^ 1; //%216 + + //debug idx value + fprintf (stderr, " KS IDX: %04d; \n", idx); + + return idx; + + +} \ No newline at end of file diff --git a/src/dmr_bs.c b/src/dmr_bs.c index a34bb57..d461f5e 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -9,6 +9,8 @@ #include "dsd.h" #include "dmr_const.h" +// #define PRINT_AMBE72 //enable to view 72-bit AMBE codewords + //A subroutine for processing each TDMA frame individually to allow for //processing voice and/or data on both BS slots (channels) simultaneously void dmrBS (dsd_opts * opts, dsd_state * state) @@ -20,6 +22,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state) char ambe_fr2[4][24]; char ambe_fr3[4][24]; + int ks_idx[2]; + ks_idx[0] = 0; + ks_idx[1] = 0; + //redundancy check (carrier signal loss event) char redundancyA[36]; char redundancyB[36]; @@ -493,6 +499,20 @@ void dmrBS (dsd_opts * opts, dsd_state * state) memcpy (m2, ambe_fr2, sizeof(m2)); memcpy (m3, ambe_fr3, sizeof(m3)); + if (state->tyt_bp == 1) + { + ks_idx[internalslot] = tyt16_ambe2_codeword_keystream(state, ambe_fr, ks_idx[internalslot], 0); + ks_idx[internalslot] = tyt16_ambe2_codeword_keystream(state, ambe_fr2, ks_idx[internalslot], 1); + ks_idx[internalslot] = tyt16_ambe2_codeword_keystream(state, ambe_fr3, ks_idx[internalslot], 0); + // ks_idx[internalslot] = 0; //move, or needed elsewhere? + } + + #ifdef PRINT_AMBE72 + ambe2_codeword_print_b(opts, ambe_fr); + ambe2_codeword_print_b(opts, ambe_fr2); + ambe2_codeword_print_b(opts, ambe_fr3); + #endif + processMbeFrame (opts, state, NULL, ambe_fr, NULL); if(internalslot == 0) { @@ -716,6 +736,10 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) char ambe_fr2[4][24]; char ambe_fr3[4][24]; + int ks_idx[2]; + ks_idx[0] = 0; + ks_idx[1] = 0; + memset (ambe_fr, 0, sizeof(ambe_fr)); memset (ambe_fr2, 0, sizeof(ambe_fr2)); memset (ambe_fr3, 0, sizeof(ambe_fr3)); @@ -922,6 +946,20 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) memcpy (m2, ambe_fr2, sizeof(m2)); memcpy (m3, ambe_fr3, sizeof(m3)); + if (state->tyt_bp == 1) + { + ks_idx[internalslot] = tyt16_ambe2_codeword_keystream(state, ambe_fr, ks_idx[internalslot], 0); + ks_idx[internalslot] = tyt16_ambe2_codeword_keystream(state, ambe_fr2, ks_idx[internalslot], 1); + ks_idx[internalslot] = tyt16_ambe2_codeword_keystream(state, ambe_fr3, ks_idx[internalslot], 0); + ks_idx[internalslot] = 0; //doesn't matter in this location + } + + #ifdef PRINT_AMBE72 + ambe2_codeword_print_b(opts, ambe_fr); + ambe2_codeword_print_b(opts, ambe_fr2); + ambe2_codeword_print_b(opts, ambe_fr3); + #endif + if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here // processMbeFrame (opts, state, NULL, ambe_fr, NULL); // processMbeFrame (opts, state, NULL, ambe_fr2, NULL); diff --git a/src/dmr_ms.c b/src/dmr_ms.c index 635c259..6e75df2 100644 --- a/src/dmr_ms.c +++ b/src/dmr_ms.c @@ -9,6 +9,8 @@ #include "dsd.h" #include "dmr_const.h" +// #define PRINT_AMBE72 //enable to view 72-bit AMBE codewords + //A subroutine for processing MS voice void dmrMS (dsd_opts * opts, dsd_state * state) { @@ -21,6 +23,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state) char ambe_fr3[4][24]; char ambe_fr4[4][24]; + int ks_idx = 0; + //memcpy of ambe_fr for late entry uint8_t m1[4][24]; uint8_t m2[4][24]; @@ -244,6 +248,20 @@ void dmrMS (dsd_opts * opts, dsd_state * state) memcpy (m2, ambe_fr2, sizeof(m2)); memcpy (m3, ambe_fr3, sizeof(m3)); + if (state->tyt_bp == 1) + { + ks_idx = tyt16_ambe2_codeword_keystream(state, ambe_fr, ks_idx, 0); + ks_idx = tyt16_ambe2_codeword_keystream(state, ambe_fr2, ks_idx, 1); + ks_idx = tyt16_ambe2_codeword_keystream(state, ambe_fr3, ks_idx, 0); + // ks_idx = 0; //needed? + } + + #ifdef PRINT_AMBE72 + ambe2_codeword_print_b(opts, ambe_fr); + ambe2_codeword_print_b(opts, ambe_fr2); + ambe2_codeword_print_b(opts, ambe_fr3); + #endif + processMbeFrame (opts, state, NULL, ambe_fr, NULL); memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); @@ -366,6 +384,8 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) memset (ambe_fr2, 0, sizeof(ambe_fr2)); memset (ambe_fr3, 0, sizeof(ambe_fr3)); + int ks_idx = 0; + //memcpy of ambe_fr for late entry uint8_t m1[4][24]; uint8_t m2[4][24]; @@ -536,6 +556,20 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) memcpy (m2, ambe_fr2, sizeof(m2)); memcpy (m3, ambe_fr3, sizeof(m3)); + if (state->tyt_bp == 1) + { + ks_idx = tyt16_ambe2_codeword_keystream(state, ambe_fr, ks_idx, 0); + ks_idx = tyt16_ambe2_codeword_keystream(state, ambe_fr2, ks_idx, 1); + ks_idx = tyt16_ambe2_codeword_keystream(state, ambe_fr3, ks_idx, 0); + // ks_idx = 0; //needed? + } + + #ifdef PRINT_AMBE72 + ambe2_codeword_print_b(opts, ambe_fr); + ambe2_codeword_print_b(opts, ambe_fr2); + ambe2_codeword_print_b(opts, ambe_fr3); + #endif + processMbeFrame (opts, state, NULL, ambe_fr, NULL); memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); diff --git a/src/dsd_main.c b/src/dsd_main.c index 72c7ab4..d082ea0 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -58,6 +58,7 @@ ctx.rounds = nbround; } + void handler(int sgnl) { UNUSED(sgnl); @@ -1080,6 +1081,10 @@ state->DMRvcR = 0; state->dropL = 256; state->dropR = 256; + + state->tyt_ap = 0; + state->tyt_bp = 0; + state->tyt_ep = 0; //ks array storage and counters memset (state->ks_octetL, 0, sizeof(state->ks_octetL)); @@ -1575,12 +1580,13 @@ printf (" \n"); printf (" -2 Manually Enter TYT and Enforce 16-bit BP Key Value (DMR) (Hex Value) \n"); printf (" \n"); - printf (" -! Manually Enter TYT Advanced Privacy AP Hex Key (see example below)\n"); + printf (" -! Manually Enter TYT and Enforce Advanced Privacy AP Hex Key (see example below)\n"); printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n"); - printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n"); - printf (" \n"); - printf (" -5 Manually Enter 48-bit BP Key Value (DMR) (Hex Value) \n"); + printf (" -! '736B9A9C5645288B 243AD5CB8701EF8A' \n"); printf (" \n"); + printf (" -5 Manually Enter TYT and Enforce Enhanced Privacy EP Hex Key (see example below)\n"); + printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n"); + printf (" -! '736B9A9C5645288B 243AD5CB8701EF8A' \n"); printf (" -k Import Key List from csv file (Decimal Format) -- Lower Case 'k'.\n"); printf (" Only supports NXDN, DMR Basic Privacy (decimal value). \n"); printf (" (dPMR and Hytera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!). \n"); @@ -1966,30 +1972,29 @@ //get user TYT BP Key and Force Its application case '2': - state.M = 0x16; //16-bit TYT 'BP' Keys + state.tyt_bp = 1; sscanf (optarg, "%llX", &state.H); state.H = state.H & 0xFFFF; //truncate to 16-bits - fprintf (stderr,"DMR TYT 16-bit Key %llX with Forced Application\n", state.H); + fprintf (stderr,"DMR TYT 16-bit Key 0x%llX with Forced Application\n", state.H); break; //get user TYT AP Key and Force Its application case '!': tyt_ap_init(); state.tyt_ap = 1; - fprintf (stderr,"DMR AP 128-bit Key %llX with Forced Application\n", state.H); + fprintf (stderr,"DMR TYT AP 128-bit Key with Forced Application\n"); break; - //Enter and Force Applicaiton of a a 48-bit AMBE Keystream (hex) for 'CCR' radios and weird 'BP' + //get user TYT EP Key and Force Its application case '5': - state.M = 0x48; //48-bit AMBE Keystream for any generic keystream application - sscanf (optarg, "%llX", &state.H); - state.H = state.H & 0xFFFFFFFFFFFF; //truncate to 48-bits - fprintf (stderr,"AMBE+2 48-bit Key %llX with Forced Application\n", state.H); + //TODO: This, or combine with above with -! AP:KEY or EP:KEY (or similar) + state.tyt_ep = 1; + fprintf (stderr,"DMR TYT EP Key with Forced Application\n"); break; case '3': opts.dmr_le = 0; - fprintf (stderr,"DMR Late Entry Encryption Identifiers Disabled (VC6 Single Burst)\n"); + fprintf (stderr,"DMRA Late Entry Encryption Identifiers Disabled\n"); break; case 'y': //use experimental 'float' audio output diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index a2f109d..173e577 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -545,53 +545,6 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a mbe_demodulateAmbe3600x2450Data (ambe_fr); state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); - //TYT (Tytera) 16-bit Key (Shuffle/Shift/Inversion Method) - if (state->M == 0x16) - { - //insert an expansion function here - unsigned long long int k = 0; - uint8_t pNT[56]; memset (pNT, 0, sizeof(pNT)); - - //I believe I have this one figured out now - //its just a shuffle, shift, invert, shift, invert, shift pattern - //could be an lfsr attached, but couldn't figure out the taps - - //below is the pattern found for the 16-bit keys listed on the right - // k = 0xFFFF00FFFF00; // 0xFFFF - // k = 0x3412CB1234ED; // 0x1234 - - //shuffle, invert, shift...and organize into proper key value - k = ((state->H & 0xFF) << 8) + ((state->H & 0xFF00) >> 8); - k = k << 8 | ((~(state->H & 0xFF) >> 0) & 0xFF); - k = k << 16 | state->H; - k = k << 8 | ((~(state->H & 0xFF00) >> 8) & 0xFF); - - //debug -- print 48-bit expanded key value - // fprintf (stderr, "K: %012llX", k); - - for (int j = 0; j < 48; j++) - { - x = ( ((k << j) & 0x800000000000) >> 47 ) & 1; - ambe_d[j] ^= x; - } - - } - - //Forced 48-bit Keystream Application "Quick and Dirty" XOR - if (state->M == 0x48) - { - // k = 0xD991633EC82E; //F811A5B94C2D ⊻ 2180C6878403 (1234 EP Key) - // k = 0x7F5363362BBE; //F811A5B94C2D ⊻ 8742C68F6793 (AAAA EP Key) - // k = 0x409231C77C08; (FFFF EP Key) - k = state->H; - for (int j = 0; j < 48; j++) //49 - { - x = ( ((k << j) & 0x800000000000) >> 47 ); - ambe_d[j] ^= x; - } - } - - //EXPERIMENTAL!! //load basic privacy key number from array by the tg value (if not forced) //currently only Moto BP and Hytera 10 Char BP @@ -951,52 +904,6 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a mbe_demodulateAmbe3600x2450Data (ambe_fr); state->errs2R += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); - //TYT (Tytera) 16-bit Key (Shuffle/Shift/Inversion Method) - if (state->M == 0x16) - { - //insert an expansion function here - unsigned long long int k = 0; - uint8_t pNT[56]; memset (pNT, 0, sizeof(pNT)); - - //I believe I have this one figured out now - //its just a shuffle, shift, invert, shift, invert, shift pattern - //could be an lfsr attached, but couldn't figure out the taps - - //below is the pattern found for the 16-bit keys listed on the right - // k = 0xFFFF00FFFF00; // 0xFFFF - // k = 0x3412CB1234ED; // 0x1234 - - //shuffle, invert, shift...and organize into proper key value - k = ((state->H & 0xFF) << 8) + ((state->H & 0xFF00) >> 8); - k = k << 8 | ((~(state->H & 0xFF) >> 0) & 0xFF); - k = k << 16 | state->H; - k = k << 8 | ((~(state->H & 0xFF00) >> 8) & 0xFF); - - //debug -- print 48-bit expanded key value - fprintf (stderr, "K: %012llX", k); - - for (int j = 0; j < 48; j++) - { - x = ( ((k << j) & 0x800000000000) >> 47 ) & 1; - ambe_d[j] ^= x; - } - - } - - //Forced 48-bit Keystream Application "Quick and Dirty" XOR - if (state->M == 0x48) - { - // k = 0xD991633EC82E; //F811A5B94C2D ⊻ 2180C6878403 (1234 EP Key) - // k = 0x7F5363362BBE; //F811A5B94C2D ⊻ 8742C68F6793 (AAAA EP Key) - // k = 0x409231C77C08; (FFFF EP Key) - k = state->H; - for (int j = 0; j < 48; j++) //49 - { - x = ( ((k << j) & 0x800000000000) >> 47 ); - ambe_d[j] ^= x; - } - } - //EXPERIMENTAL!! //load basic privacy key number from array by the tg value (if not forced) //currently only Moto BP and Hytera 10 Char BP