mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-14 01:37:25 -05:00
DMR: RAS Implementation; #369
RAS Implementation includes converting RAS 6-24 character passwords into 56-bit RAS Effective Key Values and Performing RAS Permutations on RAS Enabled Burst Types to Calculate the Correct MAC attachment to validate messages; Better Handling for RAS indicators found in BPTC 196,96 Reserved Bits and handling for RAS indicator bits found in embedded link control opcode byte; Users may either enter the RAS password with the -$ option, or the 56-bit effective key value with the -y option. Users will no longer need to use the -F option to bypass CRC errors on RAS enabled payloads when FEC does not explicitely fail. Removed the old float audio -y option.
This commit is contained in:
53
src/bptc.c
53
src/bptc.c
@@ -176,7 +176,7 @@ void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output)
|
||||
*
|
||||
* @return The total number of irrecoverable Hamming check errors
|
||||
*/
|
||||
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3])
|
||||
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];
|
||||
@@ -199,24 +199,6 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
|
||||
}
|
||||
}
|
||||
|
||||
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
|
||||
// DataMatrix[0][0] = 0; /* R(2) */
|
||||
// DataMatrix[0][1] = 0; /* R(1) */
|
||||
// DataMatrix[0][2] = 0; /* R(0) */
|
||||
|
||||
/* Init the Hamming (15,11,3) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_15_11_init();
|
||||
|
||||
/* Init the Hamming (13,9,3) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_13_9_init();
|
||||
|
||||
/* Init the Hamming error counter */
|
||||
HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each line (first time).
|
||||
* Do not check the 4th last lines */
|
||||
@@ -268,7 +250,7 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
|
||||
}
|
||||
|
||||
/* The first Hamming code check has maybe corrected bit
|
||||
* witch can be use to correct other bit, so make the
|
||||
* which can be use to correct other bit, so make the
|
||||
* same operation twice */
|
||||
|
||||
/* Reset the number of irrecoverable errors */
|
||||
@@ -359,9 +341,20 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
|
||||
* Restricted Access System (RAS) information,
|
||||
* So save these three bits after hamming correction
|
||||
* See patent US 2013/0288643 A1 */
|
||||
R[0] = DataMatrix[0][2]; /* Save R(0) */
|
||||
R[1] = DataMatrix[0][1]; /* Save R(1) */
|
||||
R[2] = DataMatrix[0][0]; /* Save R(2) */
|
||||
|
||||
//TODO: Get seperate validity for line 0 and column 0,1,2
|
||||
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) */
|
||||
}
|
||||
|
||||
if (R[0] == 0 && R[1] == 0 && R[2] == 1)
|
||||
{
|
||||
*is_ras = 1;
|
||||
}
|
||||
else *is_ras = 0;
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors */
|
||||
return HammingIrrecoverableErrorNb;
|
||||
@@ -404,11 +397,6 @@ uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDat
|
||||
}
|
||||
}
|
||||
|
||||
/* Init the Hamming (16,11,4) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_16_11_4_init();
|
||||
|
||||
/* Process the the Hamming (16,11,4) code
|
||||
* check on each line.
|
||||
* Do not check the last line (line nb 8) */
|
||||
@@ -488,6 +476,15 @@ uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDat
|
||||
/* Return the number of irrecoverable Hamming errors +
|
||||
* the number of parity check error */
|
||||
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||
|
||||
//observation shows some parity check error is okay,
|
||||
//as long as the hamming is completely okay, may be worth it
|
||||
//to only check parity bits on columns
|
||||
|
||||
if (HammingIrrecoverableErrorNb == 0 && ParityCheckErrorNb < 2)
|
||||
return (HammingIrrecoverableErrorNb);
|
||||
else return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||
|
||||
} /* End BPTC_128x77_Extract_Data() */
|
||||
|
||||
|
||||
|
||||
468
src/crypt-md5.c
Normal file
468
src/crypt-md5.c
Normal file
@@ -0,0 +1,468 @@
|
||||
//MD5 Code Originally Sourced From: https://github.com/Zunawe/md5-c
|
||||
|
||||
/*
|
||||
* Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
|
||||
* and modified slightly to be functionally identical but condensed into control structures.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
typedef struct{
|
||||
uint64_t size; // Size of input in bytes
|
||||
uint32_t buffer[4]; // Current accumulation of hash
|
||||
uint8_t input[64]; // Input to be used in the next step
|
||||
uint8_t digest[16]; // Result of algorithm
|
||||
}MD5Context;
|
||||
|
||||
/*
|
||||
* Constants defined by the MD5 algorithm
|
||||
*/
|
||||
#define A 0x67452301
|
||||
#define B 0xefcdab89
|
||||
#define C 0x98badcfe
|
||||
#define D 0x10325476
|
||||
|
||||
static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
|
||||
|
||||
static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
|
||||
|
||||
/*
|
||||
* Padding used to make the size (in bits) of the input congruent to 448 mod 512
|
||||
*/
|
||||
static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
/*
|
||||
* Bit-manipulation functions defined by the MD5 algorithm
|
||||
*/
|
||||
#define F(X, Y, Z) ((X & Y) | (~X & Z))
|
||||
#define G(X, Y, Z) ((X & Z) | (Y & ~Z))
|
||||
#define H(X, Y, Z) (X ^ Y ^ Z)
|
||||
#define I(X, Y, Z) (Y ^ (X | ~Z))
|
||||
|
||||
/*
|
||||
* Rotates a 32-bit word left by n bits
|
||||
*/
|
||||
uint32_t rotateLeft(uint32_t x, uint32_t n){
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize a context
|
||||
*/
|
||||
void md5Init(MD5Context *ctx){
|
||||
ctx->size = (uint64_t)0;
|
||||
|
||||
ctx->buffer[0] = (uint32_t)A;
|
||||
ctx->buffer[1] = (uint32_t)B;
|
||||
ctx->buffer[2] = (uint32_t)C;
|
||||
ctx->buffer[3] = (uint32_t)D;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step on 512 bits of input with the main MD5 algorithm.
|
||||
*/
|
||||
void md5Step(uint32_t *buffer, uint32_t *input){
|
||||
uint32_t AA = buffer[0];
|
||||
uint32_t BB = buffer[1];
|
||||
uint32_t CC = buffer[2];
|
||||
uint32_t DD = buffer[3];
|
||||
|
||||
uint32_t E;
|
||||
|
||||
unsigned int j;
|
||||
|
||||
for(unsigned int i = 0; i < 64; ++i){
|
||||
switch(i / 16){
|
||||
case 0:
|
||||
E = F(BB, CC, DD);
|
||||
j = i;
|
||||
break;
|
||||
case 1:
|
||||
E = G(BB, CC, DD);
|
||||
j = ((i * 5) + 1) % 16;
|
||||
break;
|
||||
case 2:
|
||||
E = H(BB, CC, DD);
|
||||
j = ((i * 3) + 5) % 16;
|
||||
break;
|
||||
default:
|
||||
E = I(BB, CC, DD);
|
||||
j = (i * 7) % 16;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t temp = DD;
|
||||
DD = CC;
|
||||
CC = BB;
|
||||
BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]);
|
||||
AA = temp;
|
||||
}
|
||||
|
||||
buffer[0] += AA;
|
||||
buffer[1] += BB;
|
||||
buffer[2] += CC;
|
||||
buffer[3] += DD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add some amount of input to the context
|
||||
*
|
||||
* If the input fills out a block of 512 bits, apply the algorithm (md5Step)
|
||||
* and save the result in the buffer. Also updates the overall size.
|
||||
*/
|
||||
void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){
|
||||
uint32_t input[16];
|
||||
unsigned int offset = ctx->size % 64;
|
||||
ctx->size += (uint64_t)input_len;
|
||||
|
||||
// Copy each byte in input_buffer into the next space in our context input
|
||||
for(unsigned int i = 0; i < input_len; ++i){
|
||||
ctx->input[offset++] = (uint8_t)*(input_buffer + i);
|
||||
|
||||
// If we've filled our context input, copy it into our local array input
|
||||
// then reset the offset to 0 and fill in a new buffer.
|
||||
// Every time we fill out a chunk, we run it through the algorithm
|
||||
// to enable some back and forth between cpu and i/o
|
||||
if(offset % 64 == 0){
|
||||
for(unsigned int j = 0; j < 16; ++j){
|
||||
// Convert to little-endian
|
||||
// The local variable `input` our 512-bit chunk separated into 32-bit words
|
||||
// we can use in calculations
|
||||
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
|
||||
(uint32_t)(ctx->input[(j * 4)]);
|
||||
}
|
||||
md5Step(ctx->buffer, input);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pad the current input to get to 448 bytes, append the size in bits to the very end,
|
||||
* and save the result of the final iteration into digest.
|
||||
*/
|
||||
void md5Finalize(MD5Context *ctx){
|
||||
uint32_t input[16];
|
||||
unsigned int offset = ctx->size % 64;
|
||||
unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;
|
||||
|
||||
// Fill in the padding and undo the changes to size that resulted from the update
|
||||
md5Update(ctx, PADDING, padding_length);
|
||||
ctx->size -= (uint64_t)padding_length;
|
||||
|
||||
// Do a final update (internal to this function)
|
||||
// Last two 32-bit words are the two halves of the size (converted from bytes to bits)
|
||||
for(unsigned int j = 0; j < 14; ++j){
|
||||
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
|
||||
(uint32_t)(ctx->input[(j * 4)]);
|
||||
}
|
||||
input[14] = (uint32_t)(ctx->size * 8);
|
||||
input[15] = (uint32_t)((ctx->size * 8) >> 32);
|
||||
|
||||
md5Step(ctx->buffer, input);
|
||||
|
||||
// Move the result into digest (convert from little-endian)
|
||||
for(unsigned int i = 0; i < 4; ++i){
|
||||
ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF));
|
||||
ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8);
|
||||
ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16);
|
||||
ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions that run the algorithm on the provided input and put the digest into result.
|
||||
* result should be able to store 16 bytes.
|
||||
*/
|
||||
void md5String(char *input, uint8_t *result){
|
||||
MD5Context ctx;
|
||||
md5Init(&ctx);
|
||||
md5Update(&ctx, (uint8_t *)input, strlen(input));
|
||||
md5Finalize(&ctx);
|
||||
|
||||
memcpy(result, ctx.digest, 16);
|
||||
}
|
||||
|
||||
void md5File(FILE *file, uint8_t *result){
|
||||
char *input_buffer = malloc(1024);
|
||||
size_t input_size = 0;
|
||||
|
||||
MD5Context ctx;
|
||||
md5Init(&ctx);
|
||||
|
||||
while((input_size = fread(input_buffer, 1, 1024, file)) > 0){
|
||||
md5Update(&ctx, (uint8_t *)input_buffer, input_size);
|
||||
}
|
||||
|
||||
md5Finalize(&ctx);
|
||||
|
||||
free(input_buffer);
|
||||
|
||||
memcpy(result, ctx.digest, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* RAS 104-bit permutation
|
||||
*
|
||||
* Generates a permutation of bit positions 0..103 using the 32-bit seed
|
||||
* (the last four active key bytes interpreted as a big-endian uint32).
|
||||
*
|
||||
* Algorithm:
|
||||
* - Maintain a circular list of the still-available positions.
|
||||
* - Repeatedly select (seed % remaining_count) steps from the current
|
||||
* position, record that index, remove it, and continue from its successor.
|
||||
*
|
||||
* Parameters:
|
||||
* seed - 32-bit seed (e.g. 0x92604BD5)
|
||||
* order - output array of 104 integers. order[i] = source bit position
|
||||
* that should be placed at output bit i.
|
||||
*/
|
||||
void ras_permute_order(uint32_t seed, int * order)
|
||||
{
|
||||
int remaining[104];
|
||||
int count = 104;
|
||||
int pos = 0; /* current index inside the remaining[] array */
|
||||
|
||||
for (int i = 0; i < 104; i++)
|
||||
remaining[i] = i;
|
||||
|
||||
for (int i = 0; i < 104; i++)
|
||||
{
|
||||
unsigned idx = seed % (unsigned)count;
|
||||
int actual = (pos + (int)idx) % count;
|
||||
|
||||
order[i] = remaining[actual];
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
//debug
|
||||
// fprintf (stderr, "\n I: %d; C: %d; P: %d; IDX: %u; ACT: %d; ORD: %d; ", i, count, pos, idx, actual, order[i]);
|
||||
#endif
|
||||
|
||||
/* remove the chosen entry */
|
||||
for (int j = actual; j < count - 1; j++)
|
||||
remaining[j] = remaining[j + 1];
|
||||
count--;
|
||||
|
||||
/* continue from the successor of the removed element */
|
||||
if (count > 0)
|
||||
pos = actual % count;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
//debug
|
||||
// fprintf(stderr, "\n Order: ");
|
||||
// for (int i = 0; i < 104; i++)
|
||||
// fprintf (stderr, "%03d,", order[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void apply_ras_permutation(const uint8_t * src, uint8_t * dst, const int * order)
|
||||
{
|
||||
for (int i = 0; i < 104; i++)
|
||||
{
|
||||
int src_bit = order[i];
|
||||
int src_byte = src_bit / 8;
|
||||
int src_off = 7 - (src_bit % 8); /* MSB of byte is lowest bit index */
|
||||
|
||||
int bit = (src[src_byte] >> src_off) & 1;
|
||||
|
||||
int dst_byte = i / 8;
|
||||
int dst_off = 7 - (i % 8);
|
||||
|
||||
if (bit)
|
||||
dst[dst_byte] |= (uint8_t)(1u << dst_off);
|
||||
}
|
||||
}
|
||||
|
||||
//Full RAS workflow, return value is the the calculated MAC attachment
|
||||
//input is a pointer to byte-wise payload from dburst of RAS enabled payloads
|
||||
uint32_t ras_mac_calculator(dsd_state * state, uint8_t * input, int input_len, int type)
|
||||
{
|
||||
|
||||
if (state->ras_effective_key == 0)
|
||||
return 0;
|
||||
|
||||
uint32_t mac = 0;
|
||||
uint8_t ras_input[13];
|
||||
memset (ras_input, 0, sizeof(ras_input));
|
||||
|
||||
for (int i = 0; i < input_len; i++)
|
||||
ras_input[i] = input[i];
|
||||
|
||||
int shift = 48;
|
||||
for (int i = input_len; i < 13; i++)
|
||||
{
|
||||
ras_input[i] = (state->ras_effective_key >> shift) & 0xFF;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
//debug input value
|
||||
if (type != 2)
|
||||
{
|
||||
fprintf (stderr, "\n RAS Input: ");
|
||||
for (int i = 0; i < 13; i++)
|
||||
fprintf (stderr, "%02X", ras_input[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t ras_output[16]; memset(ras_output, 0, sizeof(ras_output));
|
||||
|
||||
if (type != 2)
|
||||
{
|
||||
apply_ras_permutation(ras_input, ras_output, state->ras_permutation_order);
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
//debug output value
|
||||
fprintf (stderr, "\n RAS Output: ");
|
||||
for (int i = 0; i < 13; i++)
|
||||
fprintf (stderr, "%02X", ras_output[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Run Appropriate CRC or RS calculation on Permuted Output
|
||||
uint8_t output_bits[104]; memset(output_bits, 0, sizeof(output_bits));
|
||||
unpack_byte_array_into_bit_array(ras_output, output_bits, 13);
|
||||
|
||||
if (type == 0)
|
||||
mac = ComputeCrcCCITT16d(output_bits, 13*8);
|
||||
else if (type == 1)
|
||||
{
|
||||
rs_16_13_encode(ras_output);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
mac <<= 8;
|
||||
mac |= ras_output[i+13];
|
||||
}
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
mac = ComputeCrc5Bit(input);
|
||||
mac += state->ras_effective_key & 0x1F;
|
||||
mac %= 31;
|
||||
}
|
||||
|
||||
return mac;
|
||||
|
||||
}
|
||||
|
||||
void ras_effective_key_creation(dsd_state * state, char * input)
|
||||
{
|
||||
|
||||
uint8_t md5_key[30];
|
||||
memset (md5_key, 0, sizeof(md5_key));
|
||||
|
||||
uint16_t len = strlen((const char*)input);
|
||||
|
||||
//sanity check on provided char len
|
||||
if (len > 24)
|
||||
len = 24;
|
||||
|
||||
//load chars as uint8_t into key array
|
||||
for (int i = 0; i < len; i++)
|
||||
md5_key[i] = (uint8_t)input[i];
|
||||
|
||||
//debug
|
||||
fprintf (stderr, "RAS Key String: %s; LEN: %d; HEX: ", input, len);
|
||||
for (int i = 0; i < len; i++)
|
||||
fprintf (stderr, "%02X ", md5_key[i]);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
MD5Context ctx;
|
||||
md5Init(&ctx);
|
||||
md5Update(&ctx, md5_key, len);
|
||||
md5Finalize(&ctx);
|
||||
|
||||
//debug dump the digest
|
||||
fprintf (stderr, "MD5: ");
|
||||
for (int i = 0; i < 16; i++)
|
||||
fprintf (stderr, "%02X ", ctx.digest[i]);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
//The following rules are still not entirely clear, however,
|
||||
//the first one executed (last byte) has been observed to be
|
||||
//true, the SEED values are more speculative, values of
|
||||
//0 and 0x1F do not change the 5-bit checksum mod 31 (0x1F)
|
||||
|
||||
//Furthermore, it is still unclear how any rollover is handled,
|
||||
//if adding 2 is byte inclusive (effectively resetting the byte)
|
||||
//or if the value is flat 56-bit value and rollover occurs
|
||||
//to the next value over, using best guess on this
|
||||
//until further informatin comes along
|
||||
|
||||
//Below patent also suggest all bytes cannot equal zero
|
||||
//and if so, the next portion of MD5 may be used,
|
||||
//or some other method may be utilized to prevent fringe cases
|
||||
//https://patents.google.com/patent/US20130288643A1
|
||||
|
||||
//Last Byte low5 not allowed to be 0x1F (reasons unclear, but observed true)
|
||||
if ((ctx.digest[6] & 0x1F) == 0x1F)
|
||||
{
|
||||
fprintf (stderr, " Byte %d: %02X -> %02X; ", 7, ctx.digest[6], ctx.digest[6]+2);
|
||||
ctx.digest[6] += 2;
|
||||
}
|
||||
|
||||
//SEED low5 non-zero value (no change to 5-bit EMB checksum mod 31)
|
||||
if ((ctx.digest[0] & 0x1F) == 0)
|
||||
{
|
||||
fprintf (stderr, " Byte %d: %02X -> %02X; ", 1, ctx.digest[0], ctx.digest[0]+2);
|
||||
ctx.digest[0] += 2;
|
||||
}
|
||||
|
||||
//SEED low5 plus 1F (no change to 5-bit EMB checksum mod 31)
|
||||
else if ((ctx.digest[0] & 0x1F) == 0x1F)
|
||||
{
|
||||
fprintf (stderr, " Byte %d: %02X -> %02X; ", 1, ctx.digest[0], ctx.digest[0]+2);
|
||||
ctx.digest[0] += 2;
|
||||
}
|
||||
|
||||
unsigned long long int effective_key = 0;
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
effective_key <<= 8;
|
||||
effective_key |= ctx.digest[6-i];
|
||||
}
|
||||
|
||||
uint32_t ras_seed = effective_key & 0xFFFFFFFF;
|
||||
|
||||
ras_permute_order(ras_seed, state->ras_permutation_order);
|
||||
|
||||
//debug
|
||||
fprintf (stderr, "RAS Effective Key Value: %014llX;", effective_key);
|
||||
|
||||
state->ras_effective_key = effective_key;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
|
||||
}
|
||||
150
src/dmr_dburst.c
150
src/dmr_dburst.c
@@ -6,7 +6,7 @@
|
||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-12 DSD-FME Florida Man Edition
|
||||
* 2026-09 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
|
||||
@@ -51,14 +51,14 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
|
||||
//PDU Bytes and Bits
|
||||
uint8_t DMR_PDU[25];
|
||||
uint8_t DMR_PDU_bits[196];
|
||||
uint8_t DMR_PDU_bits[200];
|
||||
memset (DMR_PDU, 0, sizeof (DMR_PDU));
|
||||
memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits));
|
||||
|
||||
uint8_t R[3];
|
||||
uint8_t BPTCReservedBits = 0;
|
||||
uint8_t is_ras = 0;
|
||||
uint8_t crc_original_validity = 0;
|
||||
uint8_t is_ras = 0;
|
||||
uint8_t bptc_res_bits[3];
|
||||
memset (bptc_res_bits, 0, sizeof(bptc_res_bits));
|
||||
uint8_t crc_original_validity = 0;
|
||||
|
||||
uint32_t crcmask = 0;
|
||||
uint8_t crclen = 0;
|
||||
@@ -246,28 +246,27 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
BPTCDeInterleaveDMRData(info, BPTCDeInteleavedData);
|
||||
|
||||
/* Extract the BPTC 196,96 DMR data */
|
||||
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, R);
|
||||
|
||||
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
|
||||
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x04);
|
||||
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, bptc_res_bits, &is_ras);
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
//debug print
|
||||
//fprintf (stderr, " RAS? %X - %d %d %d", BPTCReservedBits, R[0], R[1], R[2]);
|
||||
if (bptc_res_bits[0] != 0 || bptc_res_bits[1] != 0 || bptc_res_bits[2] != 0)
|
||||
fprintf (stderr, " BPTC R BITS: %d %d %d", bptc_res_bits[0], bptc_res_bits[1], bptc_res_bits[2]);
|
||||
#endif
|
||||
|
||||
/* Convert the 96 bits BPTC data into 12 bytes */
|
||||
k = 0;
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
BPTCDmrDataByte[i] = 0;
|
||||
for(j = 0; j < 8; j++)
|
||||
{
|
||||
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] << 1;
|
||||
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] | (BPTCDmrDataBit[k] & 0x01);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
pack_bit_array_into_byte_array(BPTCDmrDataBit, BPTCDmrDataByte, 12);
|
||||
|
||||
/* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */
|
||||
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
|
||||
if (IrrecoverableErrors == 0 && BPTCDmrDataByte[1] == 0x68) is_ras = 0;
|
||||
|
||||
//make sure if this is link control, the FID is set to 0x10
|
||||
if (IrrecoverableErrors == 0 && is_lc && BPTCDmrDataByte[1] != 0x10) is_ras = 0;
|
||||
|
||||
//make sure if this is a PI header, the FID is set to 0x10
|
||||
if (IrrecoverableErrors == 0 && databurst == 0x00 && BPTCDmrDataByte[1] != 0x10) is_ras = 0;
|
||||
|
||||
/* Fill the CRC extracted */
|
||||
CRCExtracted = 0;
|
||||
for(i = 0; i < crclen; i++)
|
||||
{
|
||||
@@ -279,7 +278,20 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
CRCExtracted = CRCExtracted ^ crcmask;
|
||||
|
||||
/* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */
|
||||
if (is_lc) CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
|
||||
if (is_lc)
|
||||
{
|
||||
if (is_ras)
|
||||
{
|
||||
CRCComputed = ras_mac_calculator(state, BPTCDmrDataByte, 9, 1);
|
||||
if (CRCComputed == CRCExtracted)
|
||||
CRCCorrect = 1;
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
fprintf (stderr, " EXT: %06X; MAC: %06X;", CRCExtracted, CRCComputed);
|
||||
#endif
|
||||
}
|
||||
else CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
|
||||
}
|
||||
|
||||
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
|
||||
else if (state->data_conf_data[slot] == 0 && databurst == 0x7)
|
||||
@@ -315,20 +327,23 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
//run CCITT on other data forms
|
||||
else
|
||||
{
|
||||
CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
|
||||
if (is_ras == 1)
|
||||
{
|
||||
CRCComputed = ras_mac_calculator(state, BPTCDmrDataByte, 10, 0);
|
||||
|
||||
#ifdef DEBUG_RAS
|
||||
fprintf (stderr, " EXT: %04X; MAC: %04X;", CRCExtracted, CRCComputed);
|
||||
#endif
|
||||
}
|
||||
else CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
|
||||
|
||||
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
|
||||
else CRCCorrect = 0;
|
||||
}
|
||||
|
||||
//set the 'RAS Flag', if no irrecoverable errors but bad crc, only when enabled by user (to prevent a lot of bad data CSBKs)
|
||||
if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1;
|
||||
|
||||
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
|
||||
if (BPTCDmrDataByte[1] == 0x68) is_ras = 0;
|
||||
|
||||
//if this is a RAS system, set the CRC to okay if irrecoverable errors are okay
|
||||
//if we don't do this, then we can't view some data (CSBKs on RAS enabled systems)
|
||||
if (is_ras == 1)
|
||||
if (is_ras == 1 && state->ras_effective_key == 0)
|
||||
{
|
||||
crc_original_validity = CRCCorrect;
|
||||
CRCCorrect = 1;
|
||||
@@ -344,17 +359,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
}
|
||||
|
||||
/* Convert corrected x bytes into x*8 bits */
|
||||
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
|
||||
{
|
||||
BPTCDmrDataBit[j + 0] = (BPTCDmrDataByte[i+pdu_start] >> 7) & 0x01;
|
||||
BPTCDmrDataBit[j + 1] = (BPTCDmrDataByte[i+pdu_start] >> 6) & 0x01;
|
||||
BPTCDmrDataBit[j + 2] = (BPTCDmrDataByte[i+pdu_start] >> 5) & 0x01;
|
||||
BPTCDmrDataBit[j + 3] = (BPTCDmrDataByte[i+pdu_start] >> 4) & 0x01;
|
||||
BPTCDmrDataBit[j + 4] = (BPTCDmrDataByte[i+pdu_start] >> 3) & 0x01;
|
||||
BPTCDmrDataBit[j + 5] = (BPTCDmrDataByte[i+pdu_start] >> 2) & 0x01;
|
||||
BPTCDmrDataBit[j + 6] = (BPTCDmrDataByte[i+pdu_start] >> 1) & 0x01;
|
||||
BPTCDmrDataBit[j + 7] = (BPTCDmrDataByte[i+pdu_start] >> 0) & 0x01;
|
||||
}
|
||||
unpack_byte_array_into_bit_array(BPTCDmrDataByte, BPTCDmrDataBit, pdu_len);
|
||||
|
||||
//convert to DMR_PDU and DMR_PDU_bits
|
||||
for (i = 0; i < pdu_len; i++)
|
||||
@@ -407,6 +412,16 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
/* Compute the 5 bit CRC */
|
||||
CRCComputed = ComputeCrc5Bit(LC_DataBit);
|
||||
|
||||
//read ahead first two bytes, look for 1X10 or 2X10 pattern
|
||||
uint16_t ras_test = (uint16_t)(ConvertBitIntoBytes(&LC_DataBit[0], 16) & 0x30FF);
|
||||
if ((IrrecoverableErrors == 0) && (ras_test == 0x2010 || ras_test == 0x1010))
|
||||
{
|
||||
is_ras = 1;
|
||||
if (state->ras_effective_key != 0)
|
||||
CRCComputed = ras_mac_calculator(state, LC_DataBit, 9, 2);
|
||||
}
|
||||
else is_ras = 0;
|
||||
|
||||
if(CRCExtracted == CRCComputed) CRCCorrect = 1;
|
||||
else CRCCorrect = 0;
|
||||
|
||||
@@ -593,19 +608,8 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
else fprintf (stderr, "Reserved %d ", usbd_st);
|
||||
}
|
||||
|
||||
//set the original CRCCorrect back to its original value if the RAS flag was tripped
|
||||
if (is_ras == 1) CRCCorrect = crc_original_validity;
|
||||
|
||||
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
|
||||
// if (IrrecoverableErrors == 0 && CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) fprintf(stderr, "(CRC OK)");
|
||||
|
||||
// if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf(stderr, " (FEC OK)");
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// }
|
||||
//set the original CRCCorrect back to its original value if the RAS flag was tripped (if no key value present)
|
||||
if (is_ras == 1 && state->ras_effective_key == 0) CRCCorrect = crc_original_validity;
|
||||
|
||||
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
|
||||
{
|
||||
@@ -614,16 +618,25 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//print whether or not the 'RAS Field' bits are set to indicate RAS enabled (to be verified)
|
||||
if (is_ras == 1)
|
||||
//print whether or not the 'RAS Field' bit is set to indicate RAS
|
||||
//detected for RAS enabled burst types and disposition if key available
|
||||
if (IrrecoverableErrors == 0 && is_ras == 1 && (is_bptc || is_emb) && databurst != 0x05 && databurst != 0x07)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " -RAS ");
|
||||
//the value of this field seems to always, or usually, be 4, or just R[2] bit is set
|
||||
if (opts->payload == 1) fprintf (stderr, "%X ", BPTCReservedBits);
|
||||
fprintf (stderr, " {RAS ");
|
||||
if (state->ras_effective_key != 0 && CRCComputed != CRCExtracted)
|
||||
fprintf (stderr, "Fail} ");
|
||||
else if (state->ras_effective_key != 0 && CRCComputed == CRCExtracted)
|
||||
fprintf (stderr, "Okay} ");
|
||||
else if (state->ras_effective_key == 0)
|
||||
fprintf (stderr, "Skip} ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//might flicker the terminal on partially enabled systems, may need to find a better placement
|
||||
if (IrrecoverableErrors == 0 && (is_bptc || is_emb) && databurst != 0x05 && databurst != 0x07)
|
||||
state->dmr_is_ras = is_ras;
|
||||
|
||||
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && is_ras == 0 && databurst != 0x09 && databurst != 0x05)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
@@ -639,9 +652,24 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
fprintf (stderr, " DMR PDU Payload ");
|
||||
for (i = 0; i < pdu_len; i++)
|
||||
{
|
||||
#ifdef DEBUG_RAS
|
||||
fprintf (stderr, "%02X", DMR_PDU[i]);
|
||||
#else
|
||||
fprintf (stderr, "[%02X]", DMR_PDU[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
//RAS 5-bit - always same differential
|
||||
//calculation should be 5-bit portion of RAS Effective Key's Last byte & 0x1F
|
||||
//5-bit + CRCComputed % 31 = CRCExtracted
|
||||
#ifdef DEBUG_RAS
|
||||
if (opts->payload == 1 && is_emb && is_ras && CRCExtracted != CRCComputed && state->ras_effective_key == 0)
|
||||
{
|
||||
int32_t diff = ((int32_t)CRCExtracted - (int32_t)CRCComputed + 31) % 31;
|
||||
fprintf (stderr, " CRC CMP: %02X EXT: %02X DIFF: %02X", CRCComputed, CRCExtracted, diff);
|
||||
}
|
||||
#endif
|
||||
|
||||
//debug print
|
||||
// if (dbsn) fprintf (stderr, " SN %X", dbsn);
|
||||
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
|
||||
|
||||
@@ -32,6 +32,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
int is_alias = 0;
|
||||
int is_gps = 0;
|
||||
UNUSED(capsite);
|
||||
int is_ras = 0;
|
||||
|
||||
//XPT 'Things'
|
||||
int is_xpt = 0;
|
||||
@@ -117,6 +118,17 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
if (slot == 0) state->dmr_flco = flco;
|
||||
else state->dmr_flcoR = flco;
|
||||
|
||||
//debug output for potential RAS indicators on Moto Systems during EMB (0x2X and 0x1X indicators)
|
||||
//TODO: Either leave handling of link control as is, or rework entire file to handle all the exceptions
|
||||
//that have been added to it over the years.
|
||||
if ( (flco & 0x30) && (fid == 0x10) && (type == 3) )
|
||||
{
|
||||
is_ras = 1;
|
||||
UNUSED(is_ras);
|
||||
// flco &= 0xCF; //mask off the RAS bits
|
||||
//NOTE: Mask breaks below check on talker alias on RAS systems WIP: Fixing That
|
||||
}
|
||||
|
||||
//FID 0x10 and FLCO 0x14, 0x15, 0x16 and 0x17 confirmed as Moto EMB Alias
|
||||
//Can probably assume FID 0x10 FLCO 0x18 is Moto EMB GPS -- to be tested
|
||||
if ( fid == 0x10 && (flco == 0x14 || flco == 0x15 || flco == 0x16 || flco == 0x17 || flco == 0x18) )
|
||||
@@ -126,7 +138,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
}
|
||||
|
||||
//Embedded Talker Alias Header Only (format and len storage)
|
||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
||||
if ((fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
||||
{
|
||||
is_alias = 1;
|
||||
dmr_talker_alias_lc_header(opts, state, slot, lc_bits);
|
||||
@@ -140,7 +152,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
}
|
||||
|
||||
//Embedded GPS
|
||||
if ( (fid == 0 || fid == 0x68) && fid == 0 && type == 3 && flco == 0x08)
|
||||
if ((fid == 0 || fid == 0x68) && type == 3 && flco == 0x08)
|
||||
{
|
||||
is_gps = 1;
|
||||
dmr_embedded_gps(opts, state, lc_bits);
|
||||
@@ -502,9 +514,9 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
|
||||
//0x07 on a VLC seems to indicate a Cap+ Private Call Header
|
||||
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ or Cap+ TXI Private Call in progress
|
||||
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto (non-specific) Group Call in progress
|
||||
//its possible that both EMB FID 0x10 FLCO 0x20 and 0x23 are just Moto but non-specific (observed 0x20 on Tier 2)
|
||||
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ or Cap+ TXI Private Call in progress (RAS)
|
||||
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto (non-specific) Group Call in progress (RAS)
|
||||
//its possible that both EMB FID 0x10 FLCO 0x20 and 0x23 are just Moto but non-specific (RAS)
|
||||
|
||||
if (fid == 0x68) sprintf (state->call_string[slot], " Hytera ");
|
||||
|
||||
@@ -1191,7 +1203,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
|
||||
}
|
||||
|
||||
else if (slco == 0xF)
|
||||
else if (slco == 0xE)
|
||||
{
|
||||
uint32_t update_tgt = (uint32_t)ConvertBitIntoBytes(&slco_bits[4], 24);
|
||||
fprintf (stderr, " SLCO Cap Max Activity Update; TGT: %d;", update_tgt);
|
||||
}
|
||||
|
||||
else if (slco == 0xF) //This opcode has also been observed on Cap Max Payload Channels
|
||||
{
|
||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest LSN: %d - RS: %02X", capsite, restchannel, cap_reserved);
|
||||
|
||||
|
||||
@@ -1234,6 +1234,11 @@
|
||||
//Remus DMR End Call Alert Beep
|
||||
state->dmr_end_alert[0] = 0;
|
||||
state->dmr_end_alert[1] = 0;
|
||||
|
||||
//RAS
|
||||
memset (state->ras_permutation_order, 0, sizeof(state->ras_permutation_order));
|
||||
state->ras_effective_key = 0;
|
||||
state->dmr_is_ras = 0;
|
||||
|
||||
sprintf (state->dmr_branding, "%s", "");
|
||||
sprintf (state->dmr_branding_sub, "%s", "");
|
||||
@@ -1452,7 +1457,7 @@
|
||||
printf (" If using /dev/dsp input and output at 48k1, launch two instances of DSD-FME w -V 1 and -V 2 if needed\n");
|
||||
#endif
|
||||
printf (" -z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)\n");
|
||||
printf (" -y Enable Experimental Pulse Audio Float Audio Output\n");
|
||||
// printf (" -y Enable Experimental Pulse Audio Float Audio Output\n");
|
||||
printf (" -v <hex> Set Filtering Bitmap Options (Advanced Option)\n");
|
||||
printf (" 1 1 1 1 (0xF): PBF/LPF/HPF/HPFD on\n");
|
||||
printf ("\n");
|
||||
@@ -1571,6 +1576,12 @@
|
||||
printf (" \n");
|
||||
printf (" -A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value) \n");
|
||||
printf (" \n");
|
||||
printf (" -$ <string> Enter RAS Password 6-24 Char Key Value (DMR) (String Value) \n");
|
||||
printf (" -$ Password123\n");
|
||||
printf (" \n");
|
||||
printf (" -y <hex> Enter RAS 56-bit Effective Key Value (DMR) (14 Hex Value) \n");
|
||||
printf (" -y 6DF241BC4AE2EC\n");
|
||||
printf (" \n");
|
||||
printf (" -, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value) \n");
|
||||
printf (" -, Secure04\n");
|
||||
printf (" \n");
|
||||
@@ -1901,7 +1912,7 @@
|
||||
|
||||
exitflag = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:G:D:L:V:U:YK:b:H:X:M:NQ:WrlZTF@:!:01:2:345:6:^:7:8_:9:Ek:I:J:O+:j:,:")) != -1)
|
||||
while ((c = getopt (argc, argv, "~haepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:G:D:L:V:U:YK:b:H:X:M:NQ:WrlZTF@:!:01:2:345:6:^:7:8_:9:Ek:I:J:O+:j:,:$:y:")) != -1)
|
||||
{
|
||||
|
||||
switch (c)
|
||||
@@ -2025,6 +2036,19 @@
|
||||
auctus_keystream_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//RAS Effective Key Creation
|
||||
case '$':
|
||||
ras_effective_key_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//RAS Effective Key Direct Set
|
||||
case 'y':
|
||||
sscanf (optarg, "%llX", &state.ras_effective_key);
|
||||
state.ras_effective_key &= 0xFFFFFFFFFFFFFF; //truncate to 56-bits
|
||||
ras_permute_order((state.ras_effective_key & 0xFFFFFFFF), state.ras_permutation_order);
|
||||
fprintf (stderr,"DMR RAS 56-bit Effective Key: %llX\n", state.ras_effective_key);
|
||||
break;
|
||||
|
||||
//Straight KS Generation
|
||||
case 'S':
|
||||
straight_mod_xor_keystream_creation(&state, optarg);
|
||||
@@ -2035,10 +2059,11 @@
|
||||
fprintf (stderr,"DMRA Late Entry Encryption Identifiers Disabled\n");
|
||||
break;
|
||||
|
||||
case 'y': //use experimental 'float' audio output
|
||||
opts.floating_point = 1; //enable floating point audio output
|
||||
fprintf (stderr,"Enabling Experimental Floating Point Audio Output\n");
|
||||
break;
|
||||
//float audio experiment not going to be used going forward, very minimal benefit
|
||||
// case 'y': //use experimental 'float' audio output
|
||||
// opts.floating_point = 1; //enable floating point audio output
|
||||
// fprintf (stderr,"Enabling Experimental Floating Point Audio Output\n");
|
||||
// break;
|
||||
|
||||
case 'Y': //conventional scanner mode
|
||||
opts.scanner_mode = 1; //enable scanner
|
||||
|
||||
@@ -921,10 +921,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||||
}
|
||||
|
||||
if (state->dmr_is_ras == 1)
|
||||
printw ("{RAS}");
|
||||
|
||||
}
|
||||
else if (lls == 32 || lls == 33 || lls == 34)
|
||||
{
|
||||
printw ("DMR MS - DCC: %02i; ", state->dmr_color_code);
|
||||
|
||||
if (state->dmr_is_ras == 1)
|
||||
printw ("{RAS}");
|
||||
}
|
||||
else if (lls == 0 || lls == 1) //P1
|
||||
{
|
||||
|
||||
@@ -314,3 +314,28 @@ rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword) {
|
||||
}
|
||||
return &rs_12_9_checksum;
|
||||
}
|
||||
|
||||
//This will run a RS 12,9 encode on 9 bytes of input
|
||||
//input is an array of 12 bytes or more
|
||||
void rs_12_9_encode(uint8_t * input)
|
||||
{
|
||||
rs_12_9_codeword_t cw;
|
||||
rs_12_9_checksum_t *cs;
|
||||
|
||||
//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);
|
||||
|
||||
//Calculate the 3 parity / checksum bytes
|
||||
cs = rs_12_9_calc_checksum(&cw);
|
||||
|
||||
//Build the final 12-byte codeword
|
||||
input[9] = cs->bytes[0];
|
||||
input[10] = cs->bytes[1];
|
||||
input[11] = cs->bytes[2];
|
||||
}
|
||||
|
||||
123
src/rs-16-13.c
Normal file
123
src/rs-16-13.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* RS(16,13) encoder
|
||||
*
|
||||
* 13 data bytes + 3 parity bytes = 16-byte codeword
|
||||
*
|
||||
* Uses the same generator polynomial and GF(256) tables as the
|
||||
* DMR RS(12,9) implementation (DMR AI Spec / dmrshark / dsd):
|
||||
*
|
||||
* g(x) = x^3 + 0x40 x^2 + 0x38 x + 0x0e
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Constants
|
||||
* ----------------------------------------------------------------------- */
|
||||
#define RS_DATASIZE 13
|
||||
#define RS_CHECKSUMSIZE 3
|
||||
#define RS_CODEWORDSIZE (RS_DATASIZE + RS_CHECKSUMSIZE) /* 16 */
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Galois Field tables (GF(256) – same as DMR RS(12,9))
|
||||
* ----------------------------------------------------------------------- */
|
||||
static const uint8_t galois_exp_table[256] = {
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1D, 0x3A, 0x74, 0xE8, 0xCD, 0x87, 0x13, 0x26,
|
||||
0x4C, 0x98, 0x2D, 0x5A, 0xB4, 0x75, 0xEA, 0xC9, 0x8F, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0,
|
||||
0x9D, 0x27, 0x4E, 0x9C, 0x25, 0x4A, 0x94, 0x35, 0x6A, 0xD4, 0xB5, 0x77, 0xEE, 0xC1, 0x9F, 0x23,
|
||||
0x46, 0x8C, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x5D, 0xBA, 0x69, 0xD2, 0xB9, 0x6F, 0xDE, 0xA1,
|
||||
0x5F, 0xBE, 0x61, 0xC2, 0x99, 0x2F, 0x5E, 0xBC, 0x65, 0xCA, 0x89, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
|
||||
0xFD, 0xE7, 0xD3, 0xBB, 0x6B, 0xD6, 0xB1, 0x7F, 0xFE, 0xE1, 0xDF, 0xA3, 0x5B, 0xB6, 0x71, 0xE2,
|
||||
0xD9, 0xAF, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xBD, 0x67, 0xCE,
|
||||
0x81, 0x1F, 0x3E, 0x7C, 0xF8, 0xED, 0xC7, 0x93, 0x3B, 0x76, 0xEC, 0xC5, 0x97, 0x33, 0x66, 0xCC,
|
||||
0x85, 0x17, 0x2E, 0x5C, 0xB8, 0x6D, 0xDA, 0xA9, 0x4F, 0x9E, 0x21, 0x42, 0x84, 0x15, 0x2A, 0x54,
|
||||
0xA8, 0x4D, 0x9A, 0x29, 0x52, 0xA4, 0x55, 0xAA, 0x49, 0x92, 0x39, 0x72, 0xE4, 0xD5, 0xB7, 0x73,
|
||||
0xE6, 0xD1, 0xBF, 0x63, 0xC6, 0x91, 0x3F, 0x7E, 0xFC, 0xE5, 0xD7, 0xB3, 0x7B, 0xF6, 0xF1, 0xFF,
|
||||
0xE3, 0xDB, 0xAB, 0x4B, 0x96, 0x31, 0x62, 0xC4, 0x95, 0x37, 0x6E, 0xDC, 0xA5, 0x57, 0xAE, 0x41,
|
||||
0x82, 0x19, 0x32, 0x64, 0xC8, 0x8D, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xDD, 0xA7, 0x53, 0xA6,
|
||||
0x51, 0xA2, 0x59, 0xB2, 0x79, 0xF2, 0xF9, 0xEF, 0xC3, 0x9B, 0x2B, 0x56, 0xAC, 0x45, 0x8A, 0x09,
|
||||
0x12, 0x24, 0x48, 0x90, 0x3D, 0x7A, 0xF4, 0xF5, 0xF7, 0xF3, 0xFB, 0xEB, 0xCB, 0x8B, 0x0B, 0x16,
|
||||
0x2C, 0x58, 0xB0, 0x7D, 0xFA, 0xE9, 0xCF, 0x83, 0x1B, 0x36, 0x6C, 0xD8, 0xAD, 0x47, 0x8E, 0x01
|
||||
};
|
||||
|
||||
static const uint8_t galois_log_table[256] = {
|
||||
0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75,
|
||||
4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
|
||||
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69,
|
||||
29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166,
|
||||
6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
|
||||
54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64,
|
||||
30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
|
||||
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87,
|
||||
7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
|
||||
227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
|
||||
55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97,
|
||||
242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162,
|
||||
31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246,
|
||||
108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90,
|
||||
203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
|
||||
79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Galois multiplication
|
||||
* ----------------------------------------------------------------------- */
|
||||
static uint8_t galois_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
return galois_exp_table[(galois_log_table[a] + galois_log_table[b]) % 255];
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* RS(16,13) encoder – LFSR with the DMR generator polynomial
|
||||
*
|
||||
* genpoly coefficients (same as RS(12,9)):
|
||||
* { 0x40, 0x38, 0x0e, 0x01 }
|
||||
* ----------------------------------------------------------------------- */
|
||||
void rs16_13_encode(const uint8_t data_in[RS_DATASIZE], uint8_t codeword[RS_CODEWORDSIZE])
|
||||
{
|
||||
/* Generator polynomial coefficients from DMR AI Spec */
|
||||
static const uint8_t genpoly[] = { 0x40, 0x38, 0x0e, 0x01 };
|
||||
|
||||
uint8_t parity[3] = { 0, 0, 0 };
|
||||
uint8_t i;
|
||||
uint8_t feedback;
|
||||
|
||||
for (i = 0; i < RS_DATASIZE; i++) {
|
||||
feedback = data_in[i] ^ parity[0];
|
||||
|
||||
parity[0] = parity[1] ^ galois_mult(genpoly[2], feedback);
|
||||
parity[1] = parity[2] ^ galois_mult(genpoly[1], feedback);
|
||||
parity[2] = galois_mult(genpoly[0], feedback);
|
||||
}
|
||||
|
||||
/* Build systematic codeword: data || parity */
|
||||
memcpy(codeword, data_in, RS_DATASIZE);
|
||||
codeword[13] = parity[0];
|
||||
codeword[14] = parity[1];
|
||||
codeword[15] = parity[2];
|
||||
}
|
||||
|
||||
//This will run a RS 16,13 encode on 13 bytes of input
|
||||
//input is an array of 16 bytes or more
|
||||
void rs_16_13_encode(uint8_t * input)
|
||||
{
|
||||
|
||||
uint8_t output[16];
|
||||
memset(output, 0, sizeof(output));
|
||||
|
||||
//Calculate the 3 parity / checksum bytes
|
||||
rs16_13_encode(input, output);
|
||||
|
||||
//append the encoded parity to the input
|
||||
input[13] = output[13];
|
||||
input[14] = output[14];
|
||||
input[15] = output[15];
|
||||
}
|
||||
Reference in New Issue
Block a user