mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
106
src/crypt-etc.c
106
src/crypt-etc.c
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
14
src/dmr_bs.c
14
src/dmr_bs.c
@@ -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);
|
||||
|
||||
14
src/dmr_ms.c
14
src/dmr_ms.c
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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() */
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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')
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user