Vertex Standard 10 Char and 64 Char Encryption Support; #316

Special mode of 0:0 to apply the inversion to the interlevaed frame if present without application of a keystream for analysis;

Misc Tweaks to VTX STD ENC Header and VTX TMS message;

TG Value loading of VTX 10 char keys available only by #define VERTEX_KEY40_BY_TG which will override the Moto BP loadout;
This commit is contained in:
lwvmobile
2026-09-04 15:47:56 -04:00
parent c97400a704
commit f2254f413a
14 changed files with 492 additions and 98 deletions

View File

@@ -1,4 +1,4 @@
Build Version: AW 2026-37-g198f0ea
Build Version: AW 2026-39-gc97400a
MBElib Version: 1.3.4
CODEC2 Support Enabled
@@ -100,7 +100,6 @@ Decoder options:
-fE Decode only EDACS EA/ProVoice with ESK 0xA0*
-fm Decode only dPMR*
-l Disable DMR, dPMR, NXDN, M17 input filtering
-u <num> Unvoiced speech quality (default=3)
-xx Expect non-inverted X2-TDMA signal
-xr Expect inverted DMR signal
-xd Expect inverted ICOM dPMR signal
@@ -183,6 +182,10 @@ Advanced Decoder options:
-, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value)
-, Secure04
-u <string> Manually Enter and Enforce Vertex Standard 10 or 64 Char Hex Key
-u 10:1234567891 or 64:AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD
-u 0:0 no KS application, but apply the inversion to the interleave (clear errors on 256)
-S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)
For Example, enter 16-bit Keystream 0909 as:
-S 16:0909

View File

@@ -649,6 +649,14 @@ typedef struct
//xl specific, we need to know if the ESS is from HDU, or from LDU2
int xl_is_hdu;
//Vertex Standard Keys
// #define VERTEX_KEY40_BY_TG
// #define VERTEX_KEY256_BY_TG
char vtx256_key[64];
unsigned long long int vtx40_key;
unsigned long long int vtx256_ekey;
uint8_t vtx_key_loaded;
unsigned int debug_audio_errors;
unsigned int debug_audio_errorsR;
unsigned int debug_header_errors;
@@ -1383,6 +1391,7 @@ uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes,
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData);
uint32_t ComputeCrc32BitV(uint8_t * DMRData, uint32_t NbData);
//new simplified dmr functions
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
@@ -1646,7 +1655,7 @@ 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 / Retevis / Anytone / Kenwood / Misc DMR Encryption Modes
//Tytera / Retevis / Anytone / Kenwood / Vertex / Baofeng / Misc DMR Encryption Modes
void tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int fnum);
void tyt_ep_aes_keystream_creation(dsd_state * state, char * input);
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input);
@@ -1657,6 +1666,10 @@ void baofeng_ap_pc5_keystream_creation(dsd_state *state, char *input);
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24]);
void straight_mod_xor_keystream_creation(dsd_state * state, char * input);
void auctus_keystream_creation(dsd_state * state, char * input);
void vertex_keystream_setup(dsd_state * state, char * input);
void vertex_40_keystream_creation(dsd_state * state, unsigned long long int key_value);
void vertex_256_keystream_creation(dsd_state * state, char * key_string);
void vtx256_ambe2_interleave_inversion(char ambe_fr[4][24]);
//Kirisun
uint32_t kirisun_lfsr(unsigned long long int mi);

View File

@@ -39,6 +39,7 @@
#include <stdint.h>
#include <stddef.h>
#include "dsd.h"
#include "bp.h"
#define AES_BLOCKLEN 16
unsigned Nb = 4;
@@ -510,6 +511,57 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
}
//Vertex Standard "AES" Encryption - convert AES key into a round key at 256 Nb,Nk,Nr values
//then select entries from the BP table to invert and convert to a keystream
void vertex_256_keystream_creation(dsd_state * state, char * key_string)
{
Nb = 4;
Nk = 8;
Nr = 14;
uint8_t key[32];
memset (key, 0, sizeof(key));
parse_raw_user_string(key_string, key);
struct AES_ctx ctx;
KeyExpansion(ctx.RoundKey, key);
uint64_t vtx_key = 0;
//use the bytes from rc4 output to select 4 BP key 16-bit words
for (int i = 224; i < 228; i++)
{
vtx_key <<= 16;
vtx_key |= BPK[ctx.RoundKey[i]];
}
//invert value
vtx_key = ~vtx_key;
fprintf (stderr,"Vertex Round Key Bytes: ");
for (uint16_t i = 224; i < 228; i++)
fprintf (stderr, "%02X ", ctx.RoundKey[i]);
fprintf (stderr, "Vertex Keystream: %016llX;", (unsigned long long int)vtx_key);
fprintf (stderr, "\n");
uint8_t vtx_bytes[8];
memset (vtx_bytes, 0, sizeof(vtx_bytes));
for (int i = 0; i < 8; i++)
vtx_bytes[i] = (vtx_key >> (56-(i*8))) & 0xFF;
unpack_byte_array_into_bit_array(vtx_bytes, state->static_ks_bits[0], 8);
unpack_byte_array_into_bit_array(vtx_bytes, state->static_ks_bits[1], 8);
//hex representation of the effective keystream value
state->vtx256_ekey = convert_bits_into_output(state->static_ks_bits[0], 64);
state->vtx_key_loaded = 1;
}
//byte-wise output of AES OFB Keystream
//input iv is a 16-byte uint8_t array of initialization vector
//input key is up to 32-byte uint8_t array of key value

View File

@@ -1,4 +1,5 @@
#include "dsd.h"
#include "dmr_const.h"
void ken_dmr_scrambler_keystream_creation(dsd_state * state, char * input)
{
@@ -123,4 +124,109 @@ void straight_mod_xor_keystream_creation(dsd_state * state, char * input)
if (curr == NULL)
fprintf (stderr, "Straight KS String Malformed! No KS Created!\n");
}
//connect systems 72-bit (9-byte) Extended Encryption //TODO: Move this later
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24])
{
char interleaved[72];
memset (interleaved, 0, sizeof(interleaved));
//interleave the frame
const int *w, *x, *y, *z;
w = rW; x = rX; y = rY; z = rZ;
for (int8_t i = 0; i < 36; i++)
{
interleaved[(i*2)+0] = ambe_fr[*w][*x];
interleaved[(i*2)+1] = ambe_fr[*y][*z];
w++;
x++;
y++;
z++;
}
uint8_t ks_bytes[9]; memset(ks_bytes, 0, sizeof(ks_bytes));
uint8_t ks[72]; memset(ks, 0, sizeof(ks));
//keys are loaded in reverse byte order, stored in state->static_ks_bits[0]
for (int i = 0; i < 9; i++)
ks_bytes[i] = state->static_ks_bits[0][8-i];
//convert byte array into a bit array
unpack_byte_array_into_bit_array(ks_bytes, ks, 9);
//apply keystream to interleave
for (int8_t i = 0; i < 72; i++)
interleaved[i] ^= ks[71-i];
//deinterleave back into ambe_fr frame
w = rW; x = rX; y = rY; z = rZ;
int k = 0;
for (int8_t i = 0; i < 36; i++)
{
ambe_fr[*w][*x] = interleaved[k++];
ambe_fr[*y][*z] = interleaved[k++];
w++;
x++;
y++;
z++;
}
}
void vtx256_ambe2_interleave_inversion(char ambe_fr[4][24])
{
uint32_t silence_check = 0;
for (int i = 0; i < 20; i++)
{
silence_check <<= 1;
silence_check |= (uint8_t)ambe_fr[0][23-i];
}
if (silence_check == 0xF8014)
goto END_INV;
char interleaved[72];
memset (interleaved, 0, sizeof(interleaved));
//interleave the frame
const int *w, *x, *y, *z;
w = rW; x = rX; y = rY; z = rZ;
for (int8_t i = 0; i < 36; i++)
{
interleaved[(i*2)+0] = ambe_fr[*w][*x];
interleaved[(i*2)+1] = ambe_fr[*y][*z];
w++;
x++;
y++;
z++;
}
//invert the bits in the 49 to 71 position
for (int8_t i = 49; i < 72; i++)
interleaved[i] ^= 1;
//deinterleave back into ambe_fr frame
w = rW; x = rX; y = rY; z = rZ;
int k = 0;
for (int8_t i = 0; i < 36; i++)
{
ambe_fr[*w][*x] = interleaved[k++];
ambe_fr[*y][*z] = interleaved[k++];
w++;
x++;
y++;
z++;
}
END_INV: ; //do nothing
}

View File

@@ -4,6 +4,7 @@
*-----------------------------------------------------------------------------*/
#include "dsd.h"
#include "bp.h"
//this version is for voice, going to transition to a block output version
void rc4_voice_decrypt(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[])
@@ -245,3 +246,93 @@ void auctus_keystream_creation(dsd_state * state, char * input)
state->straight_mod = 49;
}
void vertex_40_keystream_creation(dsd_state * state, unsigned long long int key_value)
{
uint8_t key[8];
memset (key, 0, sizeof(key));
//load key from key_value
for (int i = 0; i < 5; i++)
key[i] = (key_value >> (32-(i*8))) & 0xFF;
uint8_t rc4_bytes[4];
memset (rc4_bytes, 0, sizeof(rc4_bytes));
rc4_block_output(0, 5, 4, key, rc4_bytes);
uint64_t vtx_key = 0;
//use the bytes from rc4 output to select 4 BP key 16-bit words
for (int i = 0; i < 4; i++)
{
vtx_key <<= 16;
vtx_key |= BPK[rc4_bytes[i]];
}
fprintf (stderr,"Vertex RC4 Bytes: ");
for (uint16_t i = 0; i < 8; i++)
fprintf (stderr, "%02X ", rc4_bytes[i]);
fprintf (stderr, "Vertex Keystream: %016llX;", (unsigned long long int)vtx_key);
fprintf (stderr, "\n");
uint8_t vtx_bytes[8];
memset (vtx_bytes, 0, sizeof(vtx_bytes));
for (int i = 0; i < 8; i++)
vtx_bytes[i] = (vtx_key >> (56-(i*8))) & 0xFF;
unpack_byte_array_into_bit_array(vtx_bytes, state->static_ks_bits[0], 8);
unpack_byte_array_into_bit_array(vtx_bytes, state->static_ks_bits[1], 8);
state->vtx_key_loaded = 1;
}
void vertex_keystream_setup(dsd_state * state, char * input)
{
uint16_t len = 0;
char * curr;
curr = strtok(input, ":"); //should be len (mod) of key (decimal)
if (curr != NULL)
sscanf (curr, "%hd", &len);
else goto END_KS;
//len sanity check
if (len != 0 && len != 10 && len != 64)
{
fprintf (stderr, "Vertex Standard Invalid Key Len Specified;");
goto END_KS;
}
curr = strtok(NULL, ":"); //should be key in hex
if (curr == NULL)
{
fprintf (stderr, "Vertex Standard No Key Value Specified;");
goto END_KS;
}
if (len == 10)
{
sscanf (curr, "%llx", &state->vtx40_key);
vertex_40_keystream_creation(state, state->vtx40_key);
}
else if (len == 64)
{
memcpy(state->vtx256_key, curr, 64);
vertex_256_keystream_creation(state, curr);
}
//special use case 0:0 to do the inversion, but the keystream of zero to clear the errors
//essentially no keystream is applied, but to analyze the frames, clean up the errors
else if (len == 0)
{
memset(state->static_ks_bits, 0, sizeof(state->static_ks_bits));
state->vtx256_ekey = 1;
}
END_KS: ; //do nothing
}

View File

@@ -307,55 +307,3 @@ void tyt_ep_aes_keystream_creation(dsd_state * state, char * input)
state->tyt_ep = 1;
}
//connect systems 72-bit (9-byte) Extended Encryption //TODO: Move this later
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24])
{
char interleaved[72];
memset (interleaved, 0, sizeof(interleaved));
//interleave the frame
const int *w, *x, *y, *z;
w = rW; x = rX; y = rY; z = rZ;
for (int8_t i = 0; i < 36; i++)
{
interleaved[(i*2)+0] = ambe_fr[*w][*x];
interleaved[(i*2)+1] = ambe_fr[*y][*z];
w++;
x++;
y++;
z++;
}
uint8_t ks_bytes[9]; memset(ks_bytes, 0, sizeof(ks_bytes));
uint8_t ks[72]; memset(ks, 0, sizeof(ks));
//keys are loaded in reverse byte order, stored in state->static_ks_bits[0]
for (int i = 0; i < 9; i++)
ks_bytes[i] = state->static_ks_bits[0][8-i];
//convert byte array into a bit array
unpack_byte_array_into_bit_array(ks_bytes, ks, 9);
//apply keystream to interleave
for (int8_t i = 0; i < 72; i++)
interleaved[i] ^= ks[71-i];
//deinterleave back into ambe_fr frame
w = rW; x = rX; y = rY; z = rZ;
int k = 0;
for (int8_t i = 0; i < 36; i++)
{
ambe_fr[*w][*x] = interleaved[k++];
ambe_fr[*y][*z] = interleaved[k++];
w++;
x++;
y++;
z++;
}
}

View File

@@ -187,6 +187,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera");
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera");
else if (p_mfid == 0x06) sprintf (mfid_string, "%s", "Trid/Mot");
else if (p_mfid == 0x77) sprintf (mfid_string, "%s", "VTX STD");
else if (p_mfid == 0x00) sprintf (mfid_string, "%s", "Standard");
else sprintf (mfid_string, "%s", "Other");
}
@@ -378,34 +379,25 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
if (p_sap != 1 && p_mfid == 0x77)
{
fprintf (stderr, "\n Vertex Standard PDU ENC Header:");
fprintf (stderr, " MFID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8));
fprintf (stderr, "\n Vertex Standard PDU ENC Header;");
//Unsure of how similar this is to the DMRA Enc Header, but using
//guess work and best judgment from single sample of Vertex Enhanced
//This Extended Header only seems to exist to signal encryption,
//but is otherwise mostly empty aside from a FID and single 0x01 value
//[4F][77][01][00][00][00][00][00][00][00][XX][XX]
//main issue is, I don't know if the 0x01 signalled is a key id (which is known to be 0x01)
//or if it is an encryption alg id (alg may have to be inferred based on what is loaded in radio)
//Further analysis shows that using different key types on different channels
//does not change the byte values of this header, and what is reported is that
//the Vertex Standard radios only allow one encryption type and key per channel.
//set to 0x100 so it won't trigger any weird flags, but still has a non-zero value to be checked later
if (state->currentslot == 0) state->dmr_so = 0x100;
else state->dmr_soR = 0x100;
if (state->currentslot == 0)
state->payload_keyid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8);
else state->payload_keyidR = (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8);
fprintf (stderr, " Key ID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8));
//going to use algid of 0x7 to signal a vertex standard enc method
if (state->currentslot == 0)
state->payload_algid = 0x7;
else state->payload_algidR = 0x7;
//unknown if MI, or IV is present on this header (need the AES256 Vertex PDU to compare)
if (state->currentslot == 0)
state->payload_mi = (unsigned long long int)ConvertBitIntoBytes(&dheader_bits[48], 32);
else state->payload_miR = (unsigned long long int)ConvertBitIntoBytes(&dheader_bits[48], 32);
//reset ks start value
state->data_ks_start[slot] = 0;
@@ -1115,6 +1107,53 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
decrypted_pdu = 1;
}
else if (alg == 7 && state->vtx_key_loaded == 1) //Vertex Standard, either enc type
{
pack_bit_array_into_byte_array(state->static_ks_bits[slot], ob, 8);
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%8];
decrypted_pdu = 1;
//Recalcuate CRC32
uint8_t reordered_bits[1000];
memset (reordered_bits, 0, sizeof(reordered_bits));
//rearrage for ridiculously stupid CRC32 LSO/MSO ordering
for(i = 0, j = 0; i < ctr; i+=2, j+=16)
{
reordered_bits[j + 0] = (state->dmr_pdu_sf[slot][i+1] >> 7) & 0x01;
reordered_bits[j + 1] = (state->dmr_pdu_sf[slot][i+1] >> 6) & 0x01;
reordered_bits[j + 2] = (state->dmr_pdu_sf[slot][i+1] >> 5) & 0x01;
reordered_bits[j + 3] = (state->dmr_pdu_sf[slot][i+1] >> 4) & 0x01;
reordered_bits[j + 4] = (state->dmr_pdu_sf[slot][i+1] >> 3) & 0x01;
reordered_bits[j + 5] = (state->dmr_pdu_sf[slot][i+1] >> 2) & 0x01;
reordered_bits[j + 6] = (state->dmr_pdu_sf[slot][i+1] >> 1) & 0x01;
reordered_bits[j + 7] = (state->dmr_pdu_sf[slot][i+1] >> 0) & 0x01;
reordered_bits[j + 8] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
reordered_bits[j + 9] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
reordered_bits[j + 10] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
reordered_bits[j + 11] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
reordered_bits[j + 12] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
reordered_bits[j + 13] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
reordered_bits[j + 14] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
reordered_bits[j + 15] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
}
CRCComputed = (uint32_t)ComputeCrc32BitV(reordered_bits, (ctr * 8) - 32);
CRCExtracted = (uint32_t)convert_bits_into_output(reordered_bits+((ctr * 8) - 32), 32);
if (CRCComputed == CRCExtracted)
CRCCorrect = 1;
else CRCCorrect = 0;
//set back to original value
end -= (poc + 4);
//debug
// fprintf (stderr, " CTR: %d; CRC32 CMP: %08X EXT: %08X", ctr, CRCComputed, CRCExtracted);
}
else if (alg == 5 && akl == 1 && mi != 0) //AES-256 OFB
{
int nblocks = (state->data_byte_ctr[slot] / 16) + 1;

View File

@@ -509,6 +509,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
csi72_ambe2_codeword_keystream(state, ambe_fr3);
}
if (state->vtx256_ekey != 0)
{
vtx256_ambe2_interleave_inversion(ambe_fr);
vtx256_ambe2_interleave_inversion(ambe_fr2);
vtx256_ambe2_interleave_inversion(ambe_fr3);
}
#ifdef PRINT_AMBE72
ambe2_codeword_print_i(opts, ambe_fr);
ambe2_codeword_print_i(opts, ambe_fr2);
@@ -968,6 +975,13 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
csi72_ambe2_codeword_keystream(state, ambe_fr3);
}
if (state->vtx256_ekey != 0)
{
vtx256_ambe2_interleave_inversion(ambe_fr);
vtx256_ambe2_interleave_inversion(ambe_fr2);
vtx256_ambe2_interleave_inversion(ambe_fr3);
}
#ifdef PRINT_AMBE72
ambe2_codeword_print_i(opts, ambe_fr);
ambe2_codeword_print_i(opts, ambe_fr2);

View File

@@ -270,6 +270,13 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
csi72_ambe2_codeword_keystream(state, ambe_fr3);
}
if (state->vtx256_ekey != 0)
{
vtx256_ambe2_interleave_inversion(ambe_fr);
vtx256_ambe2_interleave_inversion(ambe_fr2);
vtx256_ambe2_interleave_inversion(ambe_fr3);
}
#ifdef PRINT_AMBE72
ambe2_codeword_print_i(opts, ambe_fr);
ambe2_codeword_print_i(opts, ambe_fr2);
@@ -588,6 +595,13 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
csi72_ambe2_codeword_keystream(state, ambe_fr3);
}
if (state->vtx256_ekey != 0)
{
vtx256_ambe2_interleave_inversion(ambe_fr);
vtx256_ambe2_interleave_inversion(ambe_fr2);
vtx256_ambe2_interleave_inversion(ambe_fr3);
}
#ifdef PRINT_AMBE72
ambe2_codeword_print_i(opts, ambe_fr);
ambe2_codeword_print_i(opts, ambe_fr2);

View File

@@ -486,29 +486,24 @@ void decode_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t *
else if (port1 == 5007 && port2 == 5007)
{
//get pad amount to see where to stop parsing UTF16 text
int pad = state->data_block_poc[slot];
//sanity check
if (len > (50+pad))
len = len - pad - 50;
fprintf (stderr, "VTX STD TMS; ");
//+28, get 9 bytes for unknown "header" information
//unknown elements 0E0002000000000000, could include a len value or type (utf-16, utf-8, is07?)
//the sample has a len of 8 utf-16 chars, only way to get that is on the 2 if not byte aligned (1000)
int tmslen = input[28];
//+29, get 8 bytes for unknown "header" information
//unknown elements 0002000000000000, could include type (utf-16, utf-8, is07?)
//the sample has a len of 14 utf-16 chars, corresponding to the found 0x0E value
if (opts->payload == 1)
{
// fprintf (stderr, "Len: %03d; ", len);
fprintf (stderr, "Len: %03d; ", tmslen);
fprintf (stderr, "??: ");
for (int i = 0; i < 9; i++)
fprintf (stderr, "%02X", input[i+28]);
for (int i = 0; i < 8; i++)
fprintf (stderr, "%02X", input[i+29]);
fprintf (stderr, "; Text: ");
}
sprintf (state->dmr_lrrp_gps[slot], "VTX TMS SRC: %d; DST: %d; ", src24, dst24);
utf16_to_text(state, 1, len, input+49);
utf16_to_text(state, 1, tmslen*2, input+37);
}
else if (port1 == 5017 && port2 == 5017)
{

View File

@@ -438,3 +438,43 @@ uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData)
/* Return the CRC */
return CRC;
} /* End ComputeCrc32Bit() */
uint32_t ComputeCrc32BitV(uint8_t * DMRData, uint32_t NbData)
{
uint32_t i;
uint32_t CRC = 0x00000000; /* Initialization value = 0x00000000 */
/* Polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
* Normal = 0x04C11DB7
* Reversed = 0xEDB88320
* Reciprocal = 0xDB710641
* Reversed reciprocal = 0x82608EDB */
uint32_t Polynome = 0x04C11DB7;
for(i = 0; i < NbData; i++)
{
if(((CRC >> 31) & 1) ^ (DMRData[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
//Alternate Return Configuration for Vertex
//Encrypted PDUs that have already been reordered once before
//CRC32 CMP: 1622377A EXT: 377A1622
uint32_t a, b, c, d;
a = b = c = d = 0;
a = ((CRC >> 0) & 0xFF) << 16;
b = ((CRC >> 8) & 0xFF) << 24;
c = ((CRC >> 16) & 0xFF) << 0;
d = ((CRC >> 24) & 0xFF) << 8;
CRC = a + b + c + d;
/* Return the CRC */
return CRC;
} /* End ComputeCrc32BitV() */

View File

@@ -92,6 +92,10 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
{
encL = 0;
}
else if (state->vtx_key_loaded == 1)
{
encL = 0;
}
}
else if (state->payload_algid == 0x02 || state->payload_algid == 0x21 || state->payload_algid == 0x22)
{
@@ -118,6 +122,10 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
{
encR = 0;
}
else if (state->vtx_key_loaded == 1)
{
encR = 0;
}
}
else if (state->payload_algidR == 0x02 ||state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
{
@@ -1123,6 +1131,10 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
{
encL = 0;
}
else if (state->vtx_key_loaded == 1)
{
encL = 0;
}
}
else if (state->payload_algid == 0x02 || state->payload_algid == 0x21 || state->payload_algid == 0x22)
{
@@ -1149,6 +1161,10 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
{
encR = 0;
}
else if (state->vtx_key_loaded == 1)
{
encR = 0;
}
}
else if (state->payload_algidR == 0x02 ||state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
{

View File

@@ -437,6 +437,11 @@
state->K2 = 0;
state->K3 = 0;
state->K4 = 0;
//vertex standard keys
// memset(state->vtx256_key, 0, sizeof(state->vtx256_key));
state->vtx40_key = 0;
state->vtx256_ekey = 0;
state->vtx_key_loaded = 0;
memset (state->A1, 0, sizeof(state->A1));
memset (state->A2, 0, sizeof(state->A2));
memset (state->A3, 0, sizeof(state->A3));
@@ -1093,6 +1098,12 @@
//xl specific, we need to know if the ESS is from HDU, or from LDU2
state->xl_is_hdu = 0;
//vertex standard keys
memset(state->vtx256_key, 0, sizeof(state->vtx256_key));
state->vtx40_key = 0;
state->vtx256_ekey = 0;
state->vtx_key_loaded = 0;
//NXDN, when a new IV has arrived
state->nxdn_new_iv = 0;
@@ -1497,7 +1508,7 @@
printf (" -fE Decode only EDACS EA/ProVoice with ESK 0xA0*\n");
printf (" -fm Decode only dPMR*\n");
printf (" -l Disable DMR, dPMR, NXDN, M17 input filtering\n");
printf (" -u <num> Unvoiced speech quality (default=3)\n");
// printf (" -u <num> Unvoiced speech quality (default=3)\n");
printf (" -xx Expect non-inverted X2-TDMA signal\n");
printf (" -xr Expect inverted DMR signal\n");
printf (" -xd Expect inverted ICOM dPMR signal\n");
@@ -1585,6 +1596,10 @@
printf (" -, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value) \n");
printf (" -, Secure04\n");
printf (" \n");
printf (" -u <string> Manually Enter and Enforce Vertex Standard 10 or 64 Char Hex Key \n");
printf (" -u 10:1234567891 or 64:AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD\n");
printf (" -u 0:0 no KS application, but apply the inversion to the interleave (clear errors on 256)\n");
printf (" \n");
printf (" -S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)\n");
printf (" For Example, enter 16-bit Keystream 0909 as:\n");
printf (" -S 16:0909\n");
@@ -2049,6 +2064,12 @@
fprintf (stderr,"DMR RAS 56-bit Effective Key: %llX\n", state.ras_effective_key);
break;
//Vertex Standard KS Generation
case 'u':
vertex_keystream_setup(&state, optarg);
state.keyloader = 0;
break;
//Straight KS Generation
case 'S':
straight_mod_xor_keystream_creation(&state, optarg);
@@ -3106,18 +3127,18 @@
fprintf (stderr,"Enabling 6000 sps P25p2 all optimizations.\n");
}
break;
case 'u':
sscanf (optarg, "%i", &opts.uvquality);
if (opts.uvquality < 1)
{
opts.uvquality = 1;
}
else if (opts.uvquality > 64)
{
opts.uvquality = 64;
}
fprintf (stderr,"Setting unvoice speech quality to %i waves per band.\n", opts.uvquality);
break;
// case 'u':
// sscanf (optarg, "%i", &opts.uvquality);
// if (opts.uvquality < 1)
// {
// opts.uvquality = 1;
// }
// else if (opts.uvquality > 64)
// {
// opts.uvquality = 64;
// }
// fprintf (stderr,"Setting unvoice speech quality to %i waves per band.\n", opts.uvquality);
// break;
case 'x':
if (optarg[0] == 'x')
{

View File

@@ -599,7 +599,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
if (state->rkey_array[hash] != 0)
{
#ifdef VERTEX_KEY40_BY_TG
state->vtx40_key = state->rkey_array[hash] & 0xFFFFFFFFFF;
vertex_40_keystream_creation(state, state->vtx40_key);
#elif VERTEX_KEY256_BY_TG
//TODO: This
#else
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
#endif
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
opts->dmr_mute_encL = 0;
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
@@ -619,6 +626,20 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
}
if ( (state->vtx_key_loaded != 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
(state->vtx_key_loaded != 0 && state->forced_alg_id == 1) )
{
if (memcmp(ambe_d, ambe_silence, 49) != 0)
{
for (int i = 0; i < 49; i++)
{
if (i < 8 || i > 11)
ambe_d[i] ^= (char)state->static_ks_bits[0][i];
}
}
opts->dmr_mute_encL = 0; //shim to unmute
}
if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
(state->K1 > 0 && state->forced_alg_id == 1) )
{
@@ -1066,7 +1087,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
if (state->rkey_array[hash] != 0)
{
#ifdef VERTEX_KEY40_BY_TG
state->vtx40_key = state->rkey_array[hash] & 0xFFFFFFFFFF;
vertex_40_keystream_creation(state, state->vtx40_key);
#elif VERTEX_KEY256_BY_TG
//TODO: This
#else
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
#endif
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
opts->dmr_mute_encR = 0;
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
@@ -1086,6 +1114,20 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
}
if ( (state->vtx_key_loaded != 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ||
(state->vtx_key_loaded != 0 && state->forced_alg_id == 1) )
{
if (memcmp(ambe_d, ambe_silence, 49) != 0)
{
for (int i = 0; i < 49; i++)
{
if (i < 8 || i > 11)
ambe_d[i] ^= (char)state->static_ks_bits[1][i];
}
}
opts->dmr_mute_encR = 0; //shim to unmute
}
if ( (state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ||
(state->K1 > 0 && state->forced_alg_id == 1))
{