merge M17_Implementations/SP5WWP/m17-coder/m17-coder-sym.c into lib/m17_coder_impl: compiles but logic still remains to be checked
parent
f903603135
commit
c4c656d32f
|
@ -20,6 +20,8 @@
|
|||
|
||||
// 240620: todo uncomment #idef AES for cryptography and #ifdef ECC for signature
|
||||
|
||||
// in m17_coder_impl.h: #define AES #define ECC
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
@ -35,18 +37,16 @@
|
|||
#include "m17.h"
|
||||
|
||||
#ifdef AES
|
||||
#include "aes.hpp"
|
||||
#include "aes.h"
|
||||
#endif
|
||||
|
||||
#ifdef ECC
|
||||
#include "../../micro-ecc/uECC.h"
|
||||
#include "uECC.h"
|
||||
#endif
|
||||
|
||||
namespace gr {
|
||||
namespace m17 {
|
||||
|
||||
struct LSF lsf;
|
||||
|
||||
m17_coder::sptr
|
||||
m17_coder::make(std::string src_id,std::string dst_id,int mode,int data,int encr_type,int encr_subtype,int can,std::string meta, std::string key, bool debug, bool signed_str)
|
||||
{
|
||||
|
@ -69,22 +69,24 @@ struct LSF lsf;
|
|||
set_signed(signed_str);
|
||||
set_debug(debug);
|
||||
set_output_multiple(192);
|
||||
uint16_t ccrc=LSF_CRC(&lsf);
|
||||
lsf.crc[0]=ccrc>>8;
|
||||
lsf.crc[1]=ccrc&0xFF;
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
_got_lsf=0; //have we filled the LSF struct yet?
|
||||
_fn=0; //16-bit Frame Number (for the stream mode)
|
||||
_finished=false;
|
||||
if(_encr_type==2)
|
||||
|
||||
{
|
||||
set_key(key); // read key
|
||||
#ifdef AES
|
||||
AES_init_ctx(&_ctx, _key);
|
||||
srand(time(NULL)); //random number generator (for IV rand() seed value)
|
||||
memset(_key, 0, 32*sizeof(uint8_t));
|
||||
memset(_iv, 0, 16*sizeof(uint8_t));
|
||||
#endif
|
||||
*((int32_t*)&iv[0])=(uint32_t)time(NULL)-(uint32_t)epoch; //timestamp
|
||||
for(uint8_t i=4; i<4+10; i++) iv[i]=0; //10 random bytes TODO: replace with a rand() or pass through an additional arg
|
||||
*((int32_t*)&_iv[0])=(uint32_t)time(NULL)-(uint32_t)epoch; //timestamp
|
||||
for(uint8_t i=4; i<4+10; i++) _iv[i]=0; //10 random bytes TODO: replace with a rand() or pass through an additional arg
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void m17_coder_impl::set_signed(bool signed_str)
|
||||
|
@ -102,11 +104,11 @@ void m17_coder_impl::set_src_id(std::string src_id)
|
|||
for (int i=0;i<10;i++) {_src_id[i]=0;}
|
||||
if (src_id.length()>9) length=9; else length=src_id.length();
|
||||
for (int i=0;i<length;i++) {_src_id[i]=toupper(src_id.c_str()[i]);}
|
||||
encode_callsign_bytes(lsf.src, _src_id); // 6 byte ID <- 9 char callsign
|
||||
encode_callsign_bytes(_lsf.src, _src_id); // 6 byte ID <- 9 char callsign
|
||||
|
||||
uint16_t ccrc=LSF_CRC(&lsf);
|
||||
lsf.crc[0]=ccrc>>8;
|
||||
lsf.crc[1]=ccrc&0xFF;
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
}
|
||||
|
||||
void m17_coder_impl::set_dst_id(std::string dst_id)
|
||||
|
@ -114,10 +116,10 @@ void m17_coder_impl::set_dst_id(std::string dst_id)
|
|||
for (int i=0;i<10;i++) {_dst_id[i]=0;}
|
||||
if (dst_id.length()>9) length=9; else length=dst_id.length();
|
||||
for (int i=0;i<length;i++) {_dst_id[i]=toupper(dst_id.c_str()[i]);}
|
||||
encode_callsign_bytes(lsf.dst, _dst_id); // 6 byte ID <- 9 char callsign
|
||||
uint16_t ccrc=LSF_CRC(&lsf);
|
||||
lsf.crc[0]=ccrc>>8;
|
||||
lsf.crc[1]=ccrc&0xFF;
|
||||
encode_callsign_bytes(_lsf.dst, _dst_id); // 6 byte ID <- 9 char callsign
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
}
|
||||
|
||||
void m17_coder_impl::set_key(std::string arg) // *UTF-8* encoded byte array
|
||||
|
@ -144,26 +146,26 @@ void m17_coder_impl::set_meta(std::string meta) // either an ASCII string if enc
|
|||
if (_encr_subtype==0) // meta is \0-terminated string
|
||||
{if (meta.length()<14) length=meta.length(); else {length=14;meta[length]=0;}
|
||||
printf("%s\n",meta.c_str());
|
||||
for (int i=0;i<length;i++) {lsf.meta[i]=meta[i];}
|
||||
for (int i=0;i<length;i++) {_lsf.meta[i]=meta[i];}
|
||||
}
|
||||
else
|
||||
{length=meta.size();
|
||||
int i=0,j=0;
|
||||
while ((j<14) && (i<length))
|
||||
{if ((unsigned int)meta.data()[i]<0xc2) // https://www.utf8-chartable.de/
|
||||
{lsf.meta[j]=meta.data()[i];i++;j++;}
|
||||
{_lsf.meta[j]=meta.data()[i];i++;j++;}
|
||||
else
|
||||
{lsf.meta[j]=(meta.data()[i]-0xc2)*0x40+meta.data()[i+1];i+=2;j++;}
|
||||
{_lsf.meta[j]=(meta.data()[i]-0xc2)*0x40+meta.data()[i+1];i+=2;j++;}
|
||||
}
|
||||
length=j; // index from 0 to length-1
|
||||
printf("%d bytes: ",length);
|
||||
for (i=0;i<length;i++) printf("%02X ",lsf.meta[i]);
|
||||
for (i=0;i<length;i++) printf("%02X ",_lsf.meta[i]);
|
||||
printf("\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
uint16_t ccrc=LSF_CRC(&lsf);
|
||||
lsf.crc[0]=ccrc>>8;
|
||||
lsf.crc[1]=ccrc&0xFF;
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
}
|
||||
|
||||
void m17_coder_impl::set_mode(int mode)
|
||||
|
@ -199,14 +201,15 @@ void m17_coder_impl::set_can(int can)
|
|||
void m17_coder_impl::set_type(int mode,int data,int encr_type,int encr_subtype,int can)
|
||||
{short tmptype;
|
||||
tmptype = mode | (data<<1) | (encr_type<<3) | (encr_subtype<<5) | (can<<7);
|
||||
lsf.type[0]=tmptype>>8; // MSB
|
||||
lsf.type[1]=tmptype&0xff; // LSB
|
||||
uint16_t ccrc=LSF_CRC(&lsf);
|
||||
lsf.crc[0]=ccrc>>8;
|
||||
lsf.crc[1]=ccrc&0xFF;
|
||||
printf("Transmission type: 0x%02X%02X\n",lsf.type[0],lsf.type[1]);fflush(stdout);
|
||||
_lsf.type[0]=tmptype>>8; // MSB
|
||||
_lsf.type[1]=tmptype&0xff; // LSB
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
printf("Transmission type: 0x%02X%02X\n",_lsf.type[0],_lsf.type[1]);fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
|
@ -220,6 +223,125 @@ void m17_coder_impl::set_type(int mode,int data,int encr_type,int encr_subtype,i
|
|||
ninput_items_required[0] = noutput_items/12; // 16 inputs -> 192 outputs
|
||||
}
|
||||
|
||||
//scrambler pn sequence generation
|
||||
void m17_coder_impl::scrambler_sequence_generator()
|
||||
{
|
||||
int i = 0;
|
||||
uint32_t lfsr, bit;
|
||||
lfsr = scrambler_seed;
|
||||
|
||||
//only set if not initially set (first run), it is possible (and observed) that the scrambler_subtype can
|
||||
//change on subsequent passes if the current SEED for the LFSR falls below one of these thresholds
|
||||
if(scrambler_subtype == -1)
|
||||
{
|
||||
if (lfsr > 0 && lfsr <= 0xFF) scrambler_subtype = 0; // 8-bit key
|
||||
else if (lfsr > 0xFF && lfsr <= 0xFFFF) scrambler_subtype = 1; //16-bit key
|
||||
else if (lfsr > 0xFFFF && lfsr <= 0xFFFFFF) scrambler_subtype = 2; //24-bit key
|
||||
else scrambler_subtype = 0; // 8-bit key (default)
|
||||
}
|
||||
|
||||
//TODO: Set Frame Type based on scrambler_subtype value
|
||||
if(_debug==true)
|
||||
{
|
||||
fprintf (stderr, "\nScrambler Key: 0x%06X; Seed: 0x%06X; Subtype: %02d;", scrambler_seed, lfsr, scrambler_subtype);
|
||||
fprintf (stderr, "\n pN: ");
|
||||
}
|
||||
|
||||
//run pN sequence with taps specified
|
||||
for(i=0; i<128; i++)
|
||||
{
|
||||
//get feedback bit with specified taps, depending on the scrambler_subtype
|
||||
if(scrambler_subtype == 0)
|
||||
bit = (lfsr >> 7) ^ (lfsr >> 5) ^ (lfsr >> 4) ^ (lfsr >> 3);
|
||||
else if(scrambler_subtype == 1)
|
||||
bit = (lfsr >> 15) ^ (lfsr >> 14) ^ (lfsr >> 12) ^ (lfsr >> 3);
|
||||
else if(scrambler_subtype == 2)
|
||||
bit = (lfsr >> 23) ^ (lfsr >> 22) ^ (lfsr >> 21) ^ (lfsr >> 16);
|
||||
else bit = 0; //should never get here, but just in case
|
||||
|
||||
bit &= 1; //truncate bit to 1 bit (required since I didn't do it above)
|
||||
lfsr = (lfsr << 1) | bit; //shift LFSR left once and OR bit onto LFSR's LSB
|
||||
lfsr &= 0xFFFFFF; //truncate lfsr to 24-bit (really doesn't matter)
|
||||
scrambler_pn[i] = bit;
|
||||
|
||||
}
|
||||
//pack bit array into byte array for easy data XOR
|
||||
pack_bit_array_into_byte_array(scrambler_pn, scr_bytes, 16);
|
||||
|
||||
//save scrambler seed for next round
|
||||
scrambler_seed = lfsr;
|
||||
|
||||
//truncate seed so subtype will continue to set properly on subsequent passes
|
||||
if(scrambler_subtype == 0) scrambler_seed &= 0xFF;
|
||||
else if(scrambler_subtype == 1) scrambler_seed &= 0xFFFF;
|
||||
else if(scrambler_subtype == 2) scrambler_seed &= 0xFFFFFF;
|
||||
|
||||
if(_debug==true)
|
||||
{
|
||||
//debug packed bytes
|
||||
for(i = 0; i < 16; i++)
|
||||
fprintf (stderr, " %02X", scr_bytes[i]);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//convert a user string (as hex octets) into a uint8_t array for key
|
||||
void m17_coder_impl::parse_raw_key_string(uint8_t* dest, const char* inp)
|
||||
{
|
||||
uint16_t len = strlen(inp);
|
||||
|
||||
if(len==0) return; //return silently and pretend nothing happened
|
||||
|
||||
memset(dest, 0, len/2); //one character represents half of a byte
|
||||
|
||||
if(!(len%2)) //length even?
|
||||
{
|
||||
for(uint8_t i=0; i<len; i+=2)
|
||||
{
|
||||
if(inp[i]>='a')
|
||||
dest[i/2]|=(inp[i]-'a'+10)*0x10;
|
||||
else if(inp[i]>='A')
|
||||
dest[i/2]|=(inp[i]-'A'+10)*0x10;
|
||||
else if(inp[i]>='0')
|
||||
dest[i/2]|=(inp[i]-'0')*0x10;
|
||||
|
||||
if(inp[i+1]>='a')
|
||||
dest[i/2]|=inp[i+1]-'a'+10;
|
||||
else if(inp[i+1]>='A')
|
||||
dest[i/2]|=inp[i+1]-'A'+10;
|
||||
else if(inp[i+1]>='0')
|
||||
dest[i/2]|=inp[i+1]-'0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(inp[0]>='a')
|
||||
dest[0]|=inp[0]-'a'+10;
|
||||
else if(inp[0]>='A')
|
||||
dest[0]|=inp[0]-'A'+10;
|
||||
else if(inp[0]>='0')
|
||||
dest[0]|=inp[0]-'0';
|
||||
|
||||
for(uint8_t i=1; i<len-1; i+=2)
|
||||
{
|
||||
if(inp[i]>='a')
|
||||
dest[i/2+1]|=(inp[i]-'a'+10)*0x10;
|
||||
else if(inp[i]>='A')
|
||||
dest[i/2+1]|=(inp[i]-'A'+10)*0x10;
|
||||
else if(inp[i]>='0')
|
||||
dest[i/2+1]|=(inp[i]-'0')*0x10;
|
||||
|
||||
if(inp[i+1]>='a')
|
||||
dest[i/2+1]|=inp[i+1]-'a'+10;
|
||||
else if(inp[i+1]>='A')
|
||||
dest[i/2+1]|=inp[i+1]-'A'+10;
|
||||
else if(inp[i+1]>='0')
|
||||
dest[i/2+1]|=inp[i+1]-'0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
m17_coder_impl::general_work (int noutput_items,
|
||||
gr_vector_int &ninput_items,
|
||||
|
@ -237,34 +359,18 @@ void m17_coder_impl::set_type(int mode,int data,int encr_type,int encr_subtype,i
|
|||
uint8_t lich[6]; //48 bits packed raw, unencoded LICH
|
||||
uint8_t lich_encoded[12]; //96 bits packed, encoded LICH
|
||||
|
||||
uint8_t data[16]; //raw payload, packed bits
|
||||
uint8_t lich_cnt=0; //0..5 LICH counter, derived from the Frame Number
|
||||
uint8_t data[16], next_data[16]; //raw payload, packed bits
|
||||
|
||||
while (countout<(uint32_t)noutput_items) {
|
||||
if (countin+16<=noutput_items)
|
||||
{for (int i=0;i<16;i++) {data[i]=in[countin];countin++;}
|
||||
if(_got_lsf) //stream frames
|
||||
if(!_got_lsf) //stream frames
|
||||
{
|
||||
//send stream frame syncword
|
||||
send_syncword(out,&countout,SYNC_STR);
|
||||
//send LSF syncword
|
||||
send_syncword(out, &countout, SYNC_LSF);
|
||||
|
||||
//extract LICH from the whole LSF
|
||||
extract_LICH(lich, lich_cnt, &lsf);
|
||||
|
||||
//encode the LICH
|
||||
encode_LICH(lich_encoded, lich);
|
||||
|
||||
//unpack LICH (12 bytes)
|
||||
unpack_LICH(enc_bits, lich_encoded);
|
||||
|
||||
//encode the rest of the frame (starting at bit 96 - 0..95 are filled with LICH)
|
||||
|
||||
if(!_signed_str)
|
||||
conv_encode_stream_frame(&enc_bits[96], data, _finished ? (_fn|0x8000) : _fn);
|
||||
else //dont set the MSB is the stream is signed
|
||||
{
|
||||
conv_encode_stream_frame(&enc_bits[96], data, _fn);
|
||||
}
|
||||
//encode LSF data
|
||||
conv_encode_LSF(enc_bits, &_lsf);
|
||||
|
||||
//reorder bits
|
||||
reorder_bits(rf_bits, enc_bits);
|
||||
|
@ -272,29 +378,273 @@ void m17_coder_impl::set_type(int mode,int data,int encr_type,int encr_subtype,i
|
|||
//randomize
|
||||
randomize_bits(rf_bits);
|
||||
|
||||
//send frame data
|
||||
//send LSF data
|
||||
send_data(out, &countout, rf_bits);
|
||||
|
||||
//increment the Frame Number
|
||||
_fn = (_fn + 1) % 0x8000;
|
||||
//check the SIGNED STREAM flag
|
||||
_signed_str=(_lsf.type[0]>>3)&1;
|
||||
|
||||
//increment the LICH counter
|
||||
lich_cnt = (lich_cnt + 1) % 6;
|
||||
//set the flag
|
||||
_got_lsf=1;
|
||||
}
|
||||
|
||||
if(_finished && _signed_str) //if we are done, and the stream is signed, so we need to transmit the signature (4 frames)
|
||||
if(_debug==true)
|
||||
{
|
||||
//destination set to "ALL"
|
||||
memset(_next_lsf.dst, 0xFF, 6*sizeof(uint8_t));
|
||||
|
||||
//source set to "N0CALL"
|
||||
_next_lsf.src[0] = 0x00;
|
||||
_next_lsf.src[1] = 0x00;
|
||||
_next_lsf.src[2] = 0x4B;
|
||||
_next_lsf.src[3] = 0x13;
|
||||
_next_lsf.src[4] = 0xD1;
|
||||
_next_lsf.src[5] = 0x06;
|
||||
|
||||
if(_encryption==ENCR_AES) //AES ENC, 3200 voice
|
||||
{
|
||||
for(uint8_t i=0; i<sizeof(_priv_key); i++) //test fill
|
||||
_priv_key[i]=i;
|
||||
#ifdef ECC
|
||||
uECC_sign(priv_key, digest, sizeof(digest), _sig, curve);
|
||||
#endif
|
||||
_next_lsf.type[0] = 0x03;
|
||||
_next_lsf.type[1] = 0x95;
|
||||
}
|
||||
else if(_encryption==ENCR_SCRAM) //Scrambler ENC, 3200 Voice
|
||||
{
|
||||
_next_lsf.type[0] = 0x00;
|
||||
_next_lsf.type[1] = 0x00;
|
||||
if (scrambler_subtype==0)
|
||||
_next_lsf.type[1] = 0x0D;
|
||||
else if (scrambler_subtype==1)
|
||||
_next_lsf.type[1] = 0x2D;
|
||||
else if (scrambler_subtype==2)
|
||||
_next_lsf.type[1] = 0x4D;
|
||||
}
|
||||
else //no enc or subtype field, normal 3200 voice
|
||||
{
|
||||
_next_lsf.type[0] = 0x00;
|
||||
_next_lsf.type[1] = 0x05;
|
||||
}
|
||||
|
||||
//a signature key is loaded, OR this bit
|
||||
if(_priv_key_loaded)
|
||||
_next_lsf.type[0] |= 0x8;
|
||||
|
||||
_finished = false;
|
||||
|
||||
memset(next_data, 0, sizeof(next_data));
|
||||
memcpy(data, next_data, sizeof(data));
|
||||
if(_fn == 60)
|
||||
_finished = true;
|
||||
|
||||
//debug sig with random payloads (don't play the audio)
|
||||
for(uint8_t i = 0; i < 16; i++)
|
||||
data[i] = 0x69; //rand() & 0xFF;
|
||||
|
||||
}
|
||||
/*
|
||||
//TODO: pass some of these through arguments?
|
||||
//read data
|
||||
dummy=fread(&(lsf.dst), 6, 1, stdin);
|
||||
dummy=fread(&(lsf.src), 6, 1, stdin);
|
||||
dummy=fread(&(lsf.type), 2, 1, stdin);
|
||||
dummy=fread(&(lsf.meta), 14, 1, stdin);
|
||||
dummy=fread(data, 16, 1, stdin);
|
||||
*/
|
||||
|
||||
//AES encryption enabled - use 112 bits of IV
|
||||
if(_encryption==ENCR_AES)
|
||||
{
|
||||
memcpy(&(_lsf.meta), _iv, 14);
|
||||
_iv[14] = (_fn >> 8) & 0x7F;
|
||||
_iv[15] = (_fn >> 0) & 0xFF;
|
||||
|
||||
//re-calculate LSF CRC with IV insertion
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
}
|
||||
|
||||
while(_finished==false)
|
||||
{
|
||||
if(!_got_lsf)
|
||||
{
|
||||
//debug
|
||||
//fprintf(stderr, "LSF\n");
|
||||
|
||||
//send LSF syncword
|
||||
send_syncword(out, &countout, SYNC_LSF);
|
||||
|
||||
//encode LSF data
|
||||
conv_encode_LSF(enc_bits, &_lsf);
|
||||
|
||||
//reorder bits
|
||||
reorder_bits(rf_bits, enc_bits);
|
||||
|
||||
//randomize
|
||||
randomize_bits(rf_bits);
|
||||
|
||||
//send LSF data
|
||||
send_data(out, &countout, rf_bits);
|
||||
|
||||
//check the SIGNED STREAM flag
|
||||
_signed_str=(_lsf.type[0]>>3)&1;
|
||||
|
||||
//set the flag
|
||||
_got_lsf=1;
|
||||
}
|
||||
|
||||
if(_debug==true)
|
||||
{
|
||||
//destination set to "ALL"
|
||||
memset(_next_lsf.dst, 0xFF, 6*sizeof(uint8_t));
|
||||
|
||||
//source set to "N0CALL"
|
||||
_next_lsf.src[0] = 0x00;
|
||||
_next_lsf.src[1] = 0x00;
|
||||
_next_lsf.src[2] = 0x4B;
|
||||
_next_lsf.src[3] = 0x13;
|
||||
_next_lsf.src[4] = 0xD1;
|
||||
_next_lsf.src[5] = 0x06;
|
||||
|
||||
if(_encryption==ENCR_AES) //AES ENC, 3200 voice
|
||||
{
|
||||
_next_lsf.type[0] = 0x03;
|
||||
_next_lsf.type[1] = 0x95;
|
||||
}
|
||||
else if(_encryption==ENCR_SCRAM) //Scrambler ENC, 3200 Voice
|
||||
{
|
||||
_next_lsf.type[0] = 0x00;
|
||||
_next_lsf.type[1] = 0x00;
|
||||
if (scrambler_subtype==0)
|
||||
_next_lsf.type[1] = 0x0D;
|
||||
else if (scrambler_subtype==1)
|
||||
_next_lsf.type[1] = 0x2D;
|
||||
else if (scrambler_subtype==2)
|
||||
_next_lsf.type[1] = 0x4D;
|
||||
}
|
||||
else //no enc or subtype field, normal 3200 voice
|
||||
{
|
||||
_next_lsf.type[0] = 0x00;
|
||||
_next_lsf.type[1] = 0x05;
|
||||
}
|
||||
|
||||
//a signature key is loaded, OR this bit
|
||||
if(_priv_key_loaded)
|
||||
_next_lsf.type[0] |= 0x8;
|
||||
|
||||
_finished = false;
|
||||
|
||||
memset(next_data, 0, sizeof(next_data));
|
||||
memcpy(data, next_data, sizeof(data));
|
||||
if(_fn == 60)
|
||||
_finished = 1;
|
||||
|
||||
//debug sig with random payloads (don't play the audio)
|
||||
for(uint8_t i = 0; i < 16; i++)
|
||||
data[i] = 0x69; //rand() & 0xFF;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
//check if theres any more data
|
||||
if(fread(&(next_lsf.dst), 6, 1, stdin)<1) finished=1;
|
||||
if(fread(&(next_lsf.src), 6, 1, stdin)<1) finished=1;
|
||||
if(fread(&(next_lsf.type), 2, 1, stdin)<1) finished=1;
|
||||
if(fread(&(next_lsf.meta), 14, 1, stdin)<1) finished=1;
|
||||
*/
|
||||
if(fread(next_data, 16, 1, stdin)<1) _finished=true;
|
||||
}
|
||||
|
||||
//AES
|
||||
if(_encryption==ENCR_AES)
|
||||
{
|
||||
memcpy(&(_next_lsf.meta), _iv, 14);
|
||||
_iv[14] = (_fn >> 8) & 0x7F;
|
||||
_iv[15] = (_fn >> 0) & 0xFF;
|
||||
aes_ctr_bytewise_payload_crypt(_iv, _key, data, AES128); //hardcoded for now
|
||||
}
|
||||
|
||||
//Scrambler
|
||||
else if(_encryption==ENCR_SCRAM)
|
||||
{
|
||||
scrambler_sequence_generator();
|
||||
for(uint8_t i=0; i<16; i++)
|
||||
{
|
||||
data[i] ^= scr_bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(_finished==false)
|
||||
{
|
||||
send_syncword(out, &countout, SYNC_STR);
|
||||
extract_LICH(lich, _lich_cnt, &_lsf);
|
||||
encode_LICH(lich_encoded, lich);
|
||||
unpack_LICH(enc_bits, lich_encoded);
|
||||
conv_encode_stream_frame(&enc_bits[96], data, _fn);
|
||||
reorder_bits(rf_bits, enc_bits);
|
||||
randomize_bits(rf_bits);
|
||||
send_data(out, &countout, rf_bits);
|
||||
_fn = (_fn + 1) % 0x8000; //increment FN
|
||||
_lich_cnt = (_lich_cnt + 1) % 6; //continue with next LICH_CNT
|
||||
|
||||
//update the stream digest if required
|
||||
if(_signed_str)
|
||||
{
|
||||
for(uint8_t i=0; i<sizeof(_digest); i++)
|
||||
_digest[i]^=data[i];
|
||||
uint8_t tmp=_digest[0];
|
||||
for(uint8_t i=0; i<sizeof(_digest)-1; i++)
|
||||
_digest[i]=_digest[i+1];
|
||||
_digest[sizeof(_digest)-1]=tmp;
|
||||
}
|
||||
|
||||
//update LSF every 6 frames (superframe boundary)
|
||||
if(_fn>0 && _lich_cnt==0)
|
||||
{
|
||||
_lsf = _next_lsf;
|
||||
|
||||
//calculate LSF CRC
|
||||
uint16_t ccrc=LSF_CRC(&_lsf);
|
||||
_lsf.crc[0]=ccrc>>8;
|
||||
_lsf.crc[1]=ccrc&0xFF;
|
||||
}
|
||||
|
||||
memcpy(data, next_data, 16);
|
||||
}
|
||||
else //send last frame(s)
|
||||
{
|
||||
send_syncword(out, &countout, SYNC_STR);
|
||||
extract_LICH(lich, _lich_cnt, &_lsf);
|
||||
encode_LICH(lich_encoded, lich);
|
||||
unpack_LICH(enc_bits, lich_encoded);
|
||||
if(!_signed_str)
|
||||
conv_encode_stream_frame(&enc_bits[96], data, (_fn | 0x8000));
|
||||
else
|
||||
conv_encode_stream_frame(&enc_bits[96], data, _fn);
|
||||
reorder_bits(rf_bits, enc_bits);
|
||||
randomize_bits(rf_bits);
|
||||
send_data(out, &countout, rf_bits);
|
||||
_lich_cnt = (_lich_cnt + 1) % 6; //continue with next LICH_CNT
|
||||
|
||||
//if we are done, and the stream is signed, so we need to transmit the signature (4 frames)
|
||||
if(_signed_str)
|
||||
{
|
||||
//update digest
|
||||
for(uint8_t i=0; i<sizeof(_digest); i++)
|
||||
_digest[i]^=data[i];
|
||||
uint8_t tmp=_digest[0];
|
||||
for(uint8_t i=0; i<sizeof(_digest)-1; i++)
|
||||
_digest[i]=_digest[i+1];
|
||||
_digest[sizeof(_digest)-1]=tmp;
|
||||
|
||||
//sign the digest
|
||||
uECC_sign(_priv_key, _digest, sizeof(_digest), _sig, _curve);
|
||||
|
||||
//4 frames with 512-bit signature
|
||||
_fn = 0x7FFC; //signature has to start at 0x7FFC to end at 0x7FFF (0xFFFF with EoT marker set)
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
{
|
||||
send_syncword(out, &countout, SYNC_STR);
|
||||
extract_LICH(lich, lich_cnt, &lsf); //continue with next LICH_CNT
|
||||
extract_LICH(lich, _lich_cnt, &_lsf);
|
||||
encode_LICH(lich_encoded, lich);
|
||||
unpack_LICH(enc_bits, lich_encoded);
|
||||
conv_encode_stream_frame(&enc_bits[96], &_sig[i*16], _fn);
|
||||
|
@ -302,61 +652,36 @@ void m17_coder_impl::set_type(int mode,int data,int encr_type,int encr_subtype,i
|
|||
randomize_bits(rf_bits);
|
||||
send_data(out, &countout, rf_bits);
|
||||
_fn = (_fn<0x7FFE) ? _fn+1 : (0x7FFF|0x8000);
|
||||
lich_cnt = (lich_cnt + 1) % 6;
|
||||
_lich_cnt = (_lich_cnt + 1) % 6; //continue with next LICH_CNT
|
||||
}
|
||||
if(_debug == true)
|
||||
{
|
||||
fprintf(stderr, "Signature: ");
|
||||
for(uint8_t i=0; i<sizeof(_sig); i++)
|
||||
{
|
||||
if(i == 16 || i == 32 || i == 48)
|
||||
fprintf(stderr, "\n ");
|
||||
fprintf(stderr, "%02X", _sig[i]);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else //LSF
|
||||
{
|
||||
_got_lsf=1;
|
||||
|
||||
//send out the preamble and LSF
|
||||
send_preamble(out, &countout, 0); //0 - LSF preamble, as opposed to 1 - BERT preamble
|
||||
|
||||
//send LSF syncword
|
||||
send_syncword(out, &countout,SYNC_LSF);
|
||||
|
||||
//encode LSF data
|
||||
conv_encode_LSF(enc_bits, &lsf);
|
||||
|
||||
//reorder bits
|
||||
reorder_bits(rf_bits, enc_bits);
|
||||
|
||||
//randomize
|
||||
randomize_bits(rf_bits);
|
||||
|
||||
//send LSF data
|
||||
send_data(out, &countout, rf_bits);
|
||||
|
||||
if (_debug==true)
|
||||
{printf("TX DST: ");
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
printf("%hhX", lsf.dst[i]);
|
||||
printf(" SRC: ");
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
printf("%hhX", lsf.src[i]);
|
||||
printf(" TYPE: ");
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
printf("%hhX", lsf.type[i]);
|
||||
printf(" META: ");
|
||||
for(uint8_t i=0; i<14; i++)
|
||||
printf("%hhX", lsf.meta[i]);
|
||||
printf(" CRC: ");
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
printf("%hhX", lsf.crc[i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tell runtime system how many input items we consumed on
|
||||
// each input stream.
|
||||
//send EOT frame
|
||||
send_eot(out, &countout);
|
||||
//fprintf(stderr, "Stream has ended. Exiting.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tell runtime system how many input items we consumed on
|
||||
// each input stream.
|
||||
consume_each (countin);
|
||||
// printf(" noutput_items=%d countin=%d countout=%d\n",noutput_items,countin,countout);
|
||||
// Tell runtime system how many output items we produced.
|
||||
return countout;
|
||||
}
|
||||
return countout;
|
||||
}
|
||||
|
||||
} /* namespace m17 */
|
||||
} /* namespace gr */
|
||||
|
|
|
@ -8,10 +8,18 @@
|
|||
#ifndef INCLUDED_M17_M17_CODER_IMPL_H
|
||||
#define INCLUDED_M17_M17_CODER_IMPL_H
|
||||
|
||||
#define AES
|
||||
#define ECC
|
||||
|
||||
#include <gnuradio/m17/m17_coder.h>
|
||||
#include "m17.h" // lsf_t declaration
|
||||
|
||||
#ifdef AES
|
||||
#include "aes.hpp"
|
||||
#include "aes.h"
|
||||
#endif
|
||||
|
||||
#ifdef ECC
|
||||
#include "uECC.h"
|
||||
#endif
|
||||
|
||||
namespace gr {
|
||||
|
@ -22,31 +30,56 @@ class m17_coder_impl : public m17_coder
|
|||
private:
|
||||
unsigned char _src_id[10],_dst_id[10]; // 9 character callsign
|
||||
int _mode,_data,_encr_type,_encr_subtype,_can;
|
||||
|
||||
lsf_t _lsf, _next_lsf;
|
||||
std::string _meta;
|
||||
int _got_lsf=0;
|
||||
uint16_t _fn=0; //16-bit Frame Number (for the stream mode)
|
||||
uint8_t _lich_cnt=0; //0..5 LICH counter, derived from the Frame Number
|
||||
bool _debug=0;
|
||||
bool _signed_str,_finished;
|
||||
bool _signed_str=false,_finished=false;
|
||||
|
||||
//encryption
|
||||
uint8_t _encryption=0;
|
||||
uint8_t _digest[16]={0}; //16-byte field for the stream digest
|
||||
uint8_t _priv_key_loaded=0; //do we have a sig key loaded?
|
||||
uint8_t _priv_key[32]={0}; //private key
|
||||
uint8_t _sig[64]={0}; //ECDSA signature
|
||||
|
||||
//encryption
|
||||
#ifdef AES
|
||||
struct AES_ctx _ctx;
|
||||
#else
|
||||
#define AES_KEYLEN 32
|
||||
#define AES_BLOCKLEN 32
|
||||
//encryption
|
||||
const struct uECC_Curve_t* _curve = uECC_secp256r1();
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ENCR_NONE,
|
||||
ENCR_SCRAM,
|
||||
ENCR_AES,
|
||||
ENCR_RES //reserved
|
||||
} encr_t;
|
||||
encr_t _encryption=ENCR_NONE;
|
||||
|
||||
//AES
|
||||
typedef enum
|
||||
{
|
||||
AES128,
|
||||
AES192,
|
||||
AES256
|
||||
} aes_t;
|
||||
uint8_t _key[32];
|
||||
uint8_t _iv[16];
|
||||
time_t epoch = 1577836800L; //Jan 1, 2020, 00:00:00 UTC
|
||||
#endif
|
||||
uint8_t _key[AES_KEYLEN]; // ={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32}; //TODO: replace with a `-K` arg key entry
|
||||
uint8_t _priv_key[32];
|
||||
uint8_t _sig[64];
|
||||
uint8_t iv[AES_BLOCKLEN];
|
||||
time_t epoch = 1577836800L; //Jan 1, 2020, 00:00:00 UTC
|
||||
|
||||
#ifdef ECC
|
||||
const struct uECC_Curve_t* curve = uECC_secp256r1();
|
||||
//Scrambler
|
||||
uint8_t scr_bytes[16];
|
||||
uint8_t scrambler_pn[128];
|
||||
uint32_t scrambler_seed=0;
|
||||
int8_t scrambler_subtype = -1;
|
||||
#endif
|
||||
|
||||
public:
|
||||
void parse_raw_key_string(uint8_t* , const char* );
|
||||
void scrambler_sequence_generator();
|
||||
void set_src_id(std::string src_id);
|
||||
void set_dst_id(std::string dst_id);
|
||||
void set_key(std::string key);
|
||||
|
|
131
m17_rx.grc
131
m17_rx.grc
|
@ -1,131 +0,0 @@
|
|||
options:
|
||||
parameters:
|
||||
author: Wojciech SP5WWP
|
||||
catch_exceptions: 'True'
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: ''
|
||||
copyright: M17 Project, Jan 2024
|
||||
description: ''
|
||||
gen_cmake: 'On'
|
||||
gen_linking: dynamic
|
||||
generate_options: qt_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: m17_rx
|
||||
max_nouts: '0'
|
||||
output_language: python
|
||||
placement: (0,0)
|
||||
qt_qss_theme: ''
|
||||
realtime_scheduling: ''
|
||||
run: 'True'
|
||||
run_command: '{python} -u {filename}'
|
||||
run_options: prompt
|
||||
sizing_mode: fixed
|
||||
thread_safe_setters: ''
|
||||
title: M17 rx demo
|
||||
window_size: (1000,1000)
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 4.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: samp_rate
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '4800'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [192, 12.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_file_sink_0
|
||||
id: blocks_file_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
append: 'False'
|
||||
comment: ''
|
||||
file: /tmp/dump.bin
|
||||
type: byte
|
||||
unbuffered: 'False'
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [600, 104.0]
|
||||
rotation: 0
|
||||
state: disabled
|
||||
- name: blocks_file_source_0
|
||||
id: blocks_file_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
begin_tag: pmt.PMT_NIL
|
||||
comment: ''
|
||||
file: /tmp/fifo2
|
||||
length: '0'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
offset: '0'
|
||||
repeat: 'True'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [192, 88.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_null_sink_0
|
||||
id: blocks_null_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
bus_structure_sink: '[[0,],]'
|
||||
comment: ''
|
||||
num_inputs: '1'
|
||||
type: byte
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [616, 64.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: m17_m17_decoder_0
|
||||
id: m17_m17_decoder
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
debug_ctrl: 'True'
|
||||
debug_data: 'False'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
threshold: '2.0'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [408, 104.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
connections:
|
||||
- [blocks_file_source_0, '0', m17_m17_decoder_0, '0']
|
||||
- [m17_m17_decoder_0, '0', blocks_file_sink_0, '0']
|
||||
- [m17_m17_decoder_0, '0', blocks_null_sink_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
||||
grc_version: 3.10.10.0
|
Loading…
Reference in New Issue