kopia lustrzana https://github.com/M17-Project/M17_Implementations
Merge pull request #33 from lwvmobile/auth_plus_crypto
Manually Merge Crypto Branch in Auth Branchpull/35/head
commit
be13f76803
|
@ -9,4 +9,5 @@
|
|||
*.wav
|
||||
*.bin
|
||||
*.sym
|
||||
*.patch
|
||||
*.patch
|
||||
*.txt
|
|
@ -4,3 +4,6 @@
|
|||
[submodule "micro-ecc"]
|
||||
path = micro-ecc
|
||||
url = https://github.com/kmackay/micro-ecc
|
||||
[submodule "tinier-aes"]
|
||||
path = tinier-aes
|
||||
url = https://github.com/lwvmobile/tinier-aes
|
||||
|
|
101
README.md
101
README.md
|
@ -77,7 +77,9 @@ Packet encoding is available with `m17-packet-encoder`. Its input parameters are
|
|||
-S - source callsign (uppercase alphanumeric string) max. 9 characters
|
||||
-D - destination callsign (uppercase alphanumeric string) or ALL for broadcast
|
||||
-C - Channel Access Number (0..15, default - 0)
|
||||
-n - number of bytes (1 to 798)
|
||||
-T - SMS Text Message (example: -T 'Hello World! This is a text message')
|
||||
-R - Raw Hex Octets (example: -R 010203040506070809)
|
||||
-n - number of bytes, only when pre-encoded data passed over stdin (1 to 798)
|
||||
-o - output file path/name
|
||||
-x - binary output (M17 baseband as a packed bitstream)
|
||||
-r - raw audio output - default (single channel, signed 16-bit LE, +7168 for the +1.0 symbol, 10 samples per symbol)
|
||||
|
@ -87,7 +89,7 @@ Packet encoding is available with `m17-packet-encoder`. Its input parameters are
|
|||
-w - libsndfile wav audio output - default (single channel, signed 16-bit LE, +7168 for the +1.0 symbol, 10 samples per symbol)
|
||||
```
|
||||
|
||||
Input data is passed over stdin. Example command:
|
||||
Input data can be pre-encoded and passed over stdin. Example command:
|
||||
|
||||
`echo -en "\x05Testing M17 packet mode.\x00" | ./m17-packet-encode -S N0CALL -D ALL -C 0 -n 26 -f -o baseband.sym`
|
||||
|
||||
|
@ -97,16 +99,16 @@ Input data is passed over stdin. Example command:
|
|||
Output:
|
||||
|
||||
```
|
||||
DST: ALL FFFFFFFFFFFF
|
||||
SRC: N0CALL 00004B13D106
|
||||
Data CRC: BFEC
|
||||
LSF CRC: 432A
|
||||
SMS: Testing M17 packet mode.
|
||||
DST: ALL FFFFFFFFFFFF
|
||||
SRC: N0CALL 00004B13D106
|
||||
CAN: 00
|
||||
Data CRC: BFEC
|
||||
LSF CRC: 432A
|
||||
FN:00 (full frame)
|
||||
0554657374696E67204D3137207061636B6574206D6F64652E00
|
||||
FN:-- (ending frame)
|
||||
00BFEC0000000000000000000000000000000000000000000084
|
||||
FULL: 0554657374696E67204D3137207061636B6574206D6F64652E00BFEC
|
||||
SMS: Testing M17 packet mode.
|
||||
PKT: 05 54 65 73 74 69 6E 67 20 4D 31 37 20 70 61 63 6B 65 74 20 6D 6F 64 65 2E
|
||||
00 BF EC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
```
|
||||
|
||||
Decode packet created with above sample:
|
||||
|
@ -117,26 +119,28 @@ Output:
|
|||
|
||||
```
|
||||
DST: FFFFFFFFFFFF SRC: 00004B13D106 TYPE: 0002 META: 0000000000000000000000000000 LSF_CRC_OK
|
||||
Testing M17 packet mode.
|
||||
SMS: Testing M17 packet mode.
|
||||
```
|
||||
|
||||
Encode directly as wav format (skip sox):
|
||||
Encode User Text String as wav format:
|
||||
|
||||
`echo -en "\x05Testing M17 packet mode.\x00" | ./m17-packet-encode -S N0CALL -D AB1CDE -C 7 -n 26 -w -o baseband.wav`
|
||||
`./m17-packet-encode -S N0CALL -D AB1CDE -T 'This is an SMS Text Message Generated by m17-packet-encode' -C 7 -w -o baseband.wav`
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
DST: AB1CDE 00001F245D51
|
||||
SRC: N0CALL 00004B13D106
|
||||
Data CRC: BFEC
|
||||
LSF CRC: F754
|
||||
SMS: This is an SMS Text Message Generated by m17-packet-encode
|
||||
DST: AB1CDE 00001F245D51
|
||||
SRC: N0CALL 00004B13D106
|
||||
CAN: 07
|
||||
Data CRC: FD81
|
||||
LSF CRC: F754
|
||||
FN:00 (full frame)
|
||||
0554657374696E67204D3137207061636B6574206D6F64652E00
|
||||
FN:01 (full frame)
|
||||
FN:-- (ending frame)
|
||||
00BFEC0000000000000000000000000000000000000000000084
|
||||
FULL: 0554657374696E67204D3137207061636B6574206D6F64652E00BFEC
|
||||
SMS: Testing M17 packet mode.
|
||||
PKT: 05 54 68 69 73 20 69 73 20 61 6E 20 53 4D 53 20 54 65 78 74 20 4D 65 73 73
|
||||
61 67 65 20 47 65 6E 65 72 61 74 65 64 20 62 79 20 6D 31 37 2D 70 61 63 6B
|
||||
65 74 2D 65 6E 63 6F 64 65 00 FD 81 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
```
|
||||
|
||||
Decode with M17-FME:
|
||||
|
@ -147,26 +151,55 @@ Output:
|
|||
|
||||
```
|
||||
M17 Project - Florida Man Edition
|
||||
Build Version: 2024-1-g4f2c15c
|
||||
Session Number: A4F5
|
||||
Build Version: 2024-10-g060dd21
|
||||
Session Number: A751
|
||||
M17 Project RF Audio Frame Demodulator.
|
||||
SNDFile (.wav, .rrc) Input File: baseband.wav
|
||||
Payload Verbosity: 1;
|
||||
|
||||
|
||||
M17 LSF Frame Sync (08:57:09):
|
||||
DST: AB1CDE SRC: N0CALL CAN: 7; Data Packet
|
||||
M17 LSF Frame Sync (16:12:34):
|
||||
DST: AB1CDE SRC: N0CALL CAN: 7; Data Packet FT: 0382; ET: 0; ES: 0;
|
||||
LSF: 00 00 1F 24 5D 51 00 00 4B 13 D1 06 03 82 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 F7 54
|
||||
(CRC CHK) E: F754; C: F754;
|
||||
M17 PKT Frame Sync (08:57:09): CNT: 00; PBC: 00; EOT: 0;
|
||||
pkt: 0554657374696E67204D3137207061636B6574206D6F64652E00
|
||||
M17 PKT Frame Sync (08:57:09): CNT: 01; LST: 01; EOT: 1;
|
||||
pkt: 00BFEC0000000000000000000000000000000000000000000084 Protocol: SMS;
|
||||
SMS: Testing M17 packet mode.
|
||||
PKT: 05 54 65 73 74 69 6E 67 20 4D 31 37 20 70 61 63 6B 65 74 20 6D 6F 64 65 2E
|
||||
00 BF EC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
(CRC CHK) E: BFEC; C: BFEC;
|
||||
M17 No Frame Sync (08:57:09):
|
||||
M17 PKT Frame Sync (16:12:34): CNT: 00; PBC: 00; EOT: 0;
|
||||
pkt: 055468697320697320616E20534D532054657874204D65737300
|
||||
M17 PKT Frame Sync (16:12:34): CNT: 01; PBC: 01; EOT: 0;
|
||||
pkt: 6167652047656E657261746564206279206D31372D7061636B04
|
||||
M17 PKT Frame Sync (16:12:34): CNT: 02; LST: 12; EOT: 1;
|
||||
pkt: 65742D656E636F646500FD8100000000000000000000000000B0 Protocol: SMS;
|
||||
SMS: This is an SMS Text Message Generated by m17-packet-encode
|
||||
PKT: 05 54 68 69 73 20 69 73 20 61 6E 20 53 4D 53 20 54 65 78 74 20 4D 65 73 73
|
||||
61 67 65 20 47 65 6E 65 72 61 74 65 64 20 62 79 20 6D 31 37 2D 70 61 63 6B
|
||||
65 74 2D 65 6E 63 6F 64 65 00 FD 81 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
(CRC CHK) E: FD81; C: FD81;
|
||||
```
|
||||
|
||||
Encode Raw Hex Octet String as float symbol format:
|
||||
|
||||
`./m17-packet-encode -S N0CALL -D AB1CDE -R 010203040506070809 -C 7 -f -o float.sym`
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
Raw Len: 9; Raw Octets: 01 02 03 04 05 06 07 08 09
|
||||
DST: AB1CDE 00001F245D51
|
||||
SRC: N0CALL 00004B13D106
|
||||
CAN: 07
|
||||
Data CRC: D7CE
|
||||
LSF CRC: F754
|
||||
FN:-- (ending frame)
|
||||
PKT: 01 02 03 04 05 06 07 08 09 D7 CE 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
```
|
||||
|
||||
Decode (rolling) packets created with above sample:
|
||||
|
||||
`tail -f float.sym | ./m17-packet-decode`
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
DST: 00001F245D51 SRC: 00004B13D106 TYPE: 0382 META: 0000000000000000000000000000 LSF_CRC_OK
|
||||
PKT: 01 02 03 04 05 06 07 08 09 D7 CE
|
||||
```
|
|
@ -1,5 +1,5 @@
|
|||
m17-coder-sym: m17-coder-sym.c
|
||||
gcc -O2 -Wall -Wextra m17-coder-sym.c ../../micro-ecc/uECC.c -o m17-coder-sym -lm -lm17
|
||||
gcc -O2 -Wall -Wextra m17-coder-sym.c ../../micro-ecc/uECC.c ../../tinier-aes/aes.c -o m17-coder-sym -lm -lm17
|
||||
|
||||
clean:
|
||||
rm -f m17-coder-sym
|
||||
|
|
|
@ -2,14 +2,29 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
//libm17
|
||||
#include "../../libm17/m17.h"
|
||||
//micro-ecc
|
||||
#include "../../micro-ecc/uECC.h"
|
||||
//tinier-aes
|
||||
#include "../../tinier-aes/aes.h"
|
||||
|
||||
//#define FN60_DEBUG
|
||||
|
||||
//TODO: Load Signature Private and Public Keys from file
|
||||
//TODO: More Thorough Testing to make sure everything is good
|
||||
//TODO: Round of Cleanup (and test after cleaning up!
|
||||
//TODO: OR Frametype Bits depending on encryption type, subtype, and signed sig
|
||||
|
||||
//Wishlist: Please Woj, can we use the subtype on AES to signal AES 128, AES 192, or AES 256?
|
||||
// We already to it for Scrambler
|
||||
|
||||
//Wishlist: way to fix this warning without changing uECC source code or disabling -Wall -Wextra
|
||||
//../../micro-ecc/curve-specific.inc:544:59: warning: unused parameter ‘curve’ [-Wunused-parameter]
|
||||
//544 | static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) {
|
||||
|
||||
struct LSF lsf, next_lsf;
|
||||
|
||||
uint8_t lich[6]; //48 bits packed raw, unencoded LICH
|
||||
|
@ -29,15 +44,100 @@ uint8_t finished=0; //no more data at stdin?
|
|||
//used for signatures
|
||||
uint8_t digest[16]={0}; //16-byte field for the stream digest
|
||||
uint8_t signed_str=0; //is the stream supposed to be signed?
|
||||
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
|
||||
|
||||
int dummy=0; //dummy var to make compiler quieter
|
||||
|
||||
//AES
|
||||
uint8_t encryption=0;
|
||||
int aes_type = 1; //1=AES128, 2=AES192, 3=AES256
|
||||
uint8_t key[32];
|
||||
uint8_t iv[16];
|
||||
time_t epoch = 1577836800L; //Jan 1, 2020, 00:00:00 UTC
|
||||
|
||||
//Scrambler
|
||||
uint8_t scr_bytes[16];
|
||||
uint8_t scrambler_pn[128];
|
||||
uint32_t scrambler_seed=0;
|
||||
int8_t scrambler_subtype = -1;
|
||||
|
||||
//debug mode (preset lsf, type, zero payload for enc testing, etc)
|
||||
uint8_t debug_mode=0;
|
||||
|
||||
//scrambler pn sequence generation
|
||||
void 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_mode > 1)
|
||||
{
|
||||
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;
|
||||
if (scrambler_subtype == 1) scrambler_seed &= 0xFFFF;
|
||||
if (scrambler_subtype == 2) scrambler_seed &= 0xFFFFFF;
|
||||
else scrambler_seed &= 0xFF;
|
||||
|
||||
if (debug_mode > 1)
|
||||
{
|
||||
//debug packed bytes
|
||||
for (i = 0; i < 16; i++)
|
||||
fprintf (stderr, " %02X", scr_bytes[i]);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, "-s - Private key for ECDSA signature, 32 bytes (-s [hex_string|key_file]),\n");
|
||||
fprintf(stderr, "-K - AES encryption key (-K [hex_string|text_file]),\n");
|
||||
fprintf(stderr, "-k - Scrambler encryption seed value (-k [hex_string]),\n");
|
||||
fprintf(stderr, "-D - Debug mode,\n");
|
||||
fprintf(stderr, "-h - help / print usage\n");
|
||||
}
|
||||
|
||||
|
@ -100,6 +200,10 @@ void parse_raw_key_string(uint8_t* dest, const char* inp)
|
|||
//main routine
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
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));
|
||||
|
||||
//scan command line options for input data (purely optional)
|
||||
if(argc>=1)
|
||||
{
|
||||
|
@ -118,9 +222,123 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
parse_raw_key_string(priv_key, argv[i+1]);
|
||||
|
||||
priv_key_loaded=1; //mainly for debug mode
|
||||
i++;
|
||||
}
|
||||
else if(argv[i][1]=='K') //-K - AES Encryption
|
||||
{
|
||||
if(strstr(argv[i+1], ".")) //if the next arg contains a dot - read key from a text file
|
||||
{
|
||||
char fname[128]={'\0'}; //output file
|
||||
if(strlen(&argv[i+1][0])>0)
|
||||
memcpy(fname, &argv[i+1][0], strlen(argv[i+1]));
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid filename. Exiting...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* fp;
|
||||
char source_str[64];
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if(!fp)
|
||||
{
|
||||
fprintf(stderr, "Failed to load file %s.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//size check
|
||||
size_t len = fread(source_str, 1, 64, fp); //TODO: check length
|
||||
fclose(fp);
|
||||
|
||||
if(len==256/4)
|
||||
fprintf(stderr, "AES256");
|
||||
else if(len==192/4)
|
||||
fprintf(stderr, "AES192");
|
||||
else if(len==128/4)
|
||||
fprintf(stderr, "AES128");
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid key length.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_raw_key_string(key, source_str);
|
||||
|
||||
fprintf(stderr, " key:");
|
||||
for(uint8_t i=0; i<len/2; i++)
|
||||
{
|
||||
if(i==16)
|
||||
fprintf(stderr, "\n ");
|
||||
fprintf(stderr, " %02X", key[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
//size check
|
||||
size_t len = strlen(argv[i+1]);
|
||||
|
||||
if(len==256/4)
|
||||
fprintf(stderr, "AES256");
|
||||
else if(len==192/4)
|
||||
fprintf(stderr, "AES192");
|
||||
else if(len==128/4)
|
||||
fprintf(stderr, "AES128");
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid key length.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_raw_key_string(key, argv[i+1]);
|
||||
|
||||
fprintf(stderr, " key:");
|
||||
for(uint8_t i=0; i<len/2; i++)
|
||||
{
|
||||
if(i==16)
|
||||
fprintf(stderr, "\n ");
|
||||
fprintf(stderr, " %02X", key[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
encryption=2; //AES key was passed
|
||||
}
|
||||
else if(argv[i][1]=='k') //-k - Scrambler Encryption
|
||||
{
|
||||
//length check
|
||||
uint8_t length=strlen(argv[i+1]);
|
||||
if(length==0 || length>24/4) //24-bit is the largest seed value
|
||||
{
|
||||
fprintf(stderr, "Invalid key length.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_raw_key_string(key, argv[i+1]);
|
||||
scrambler_seed = (key[0] << 16) | (key[1] << 8) | (key[2] << 0);
|
||||
|
||||
if(length<=2)
|
||||
{
|
||||
scrambler_seed = scrambler_seed >> 16;
|
||||
fprintf(stderr, "Scrambler key: 0x%02X (8-bit)\n", scrambler_seed);
|
||||
}
|
||||
else if(length<=4)
|
||||
{
|
||||
scrambler_seed = scrambler_seed >> 8;
|
||||
fprintf(stderr, "Scrambler key: 0x%04X (16-bit)\n", scrambler_seed);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Scrambler key: 0x%06X (24-bit)\n", scrambler_seed);
|
||||
|
||||
encryption=1; //Scrambler key was passed
|
||||
}
|
||||
else if(argv[i][1]=='D') //-D - Debug Mode
|
||||
{
|
||||
debug_mode=1;
|
||||
}
|
||||
|
||||
else if(argv[i][1]=='h') //-h - help / usage
|
||||
{
|
||||
usage();
|
||||
|
@ -136,6 +354,14 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
if(encryption==2)
|
||||
{
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
iv[i] = ((uint32_t)(time(NULL)&0xFFFFFFFF)-(uint32_t)epoch) >> (24-(i*8));
|
||||
for(uint8_t i=3; i<14; i++)
|
||||
iv[i] = rand() & 0xFF; //10 random bytes
|
||||
}
|
||||
|
||||
const struct uECC_Curve_t* curve = uECC_secp256r1();
|
||||
|
||||
//send out the preamble
|
||||
|
@ -143,12 +369,76 @@ int main(int argc, char* argv[])
|
|||
send_preamble(frame_buff, &frame_buff_cnt, 0); //0 - LSF preamble, as opposed to 1 - BERT preamble
|
||||
fwrite((uint8_t*)frame_buff, SYM_PER_FRA*sizeof(float), 1, stdout);
|
||||
|
||||
//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);
|
||||
if (debug_mode == 1)
|
||||
{
|
||||
//broadcast
|
||||
memset(lsf.dst, 0xFF, 6*sizeof(uint8_t));
|
||||
|
||||
//N0CALL
|
||||
lsf.src[0] = 0x00;
|
||||
lsf.src[1] = 0x00;
|
||||
lsf.src[2] = 0x4B;
|
||||
lsf.src[3] = 0x13;
|
||||
lsf.src[4] = 0xD1;
|
||||
lsf.src[5] = 0x06;
|
||||
|
||||
if (encryption == 2) //AES ENC, 3200 voice
|
||||
{
|
||||
lsf.type[0] = 0x03;
|
||||
lsf.type[1] = 0x95;
|
||||
}
|
||||
else if (encryption == 1) //Scrambler ENC, 3200 Voice
|
||||
{
|
||||
lsf.type[0] = 0x03;
|
||||
lsf.type[1] = 0xCD;
|
||||
}
|
||||
else //no enc or subtype field, normal 3200 voice
|
||||
{
|
||||
lsf.type[0] = 0x00;
|
||||
lsf.type[1] = 0x05;
|
||||
}
|
||||
|
||||
//a signature key is loaded, OR this bit
|
||||
if(priv_key_loaded)
|
||||
{
|
||||
signed_str = 1;
|
||||
lsf.type[0] |= 0x8;
|
||||
}
|
||||
|
||||
//calculate LSF CRC (unclear whether or not this is only
|
||||
//needed here for debug, or if this is missing on every initial LSF)
|
||||
uint16_t ccrc=LSF_CRC(&lsf);
|
||||
lsf.crc[0]=ccrc>>8;
|
||||
lsf.crc[1]=ccrc&0xFF;
|
||||
|
||||
finished = 0;
|
||||
|
||||
//debug sig with random payloads (don't play the audio)
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
data[i] = 0x69; //rand() & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
//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==2)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -183,12 +473,79 @@ int main(int argc, char* argv[])
|
|||
got_lsf=1;
|
||||
}
|
||||
|
||||
//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=1;
|
||||
if (debug_mode == 1)
|
||||
{
|
||||
//broadcast
|
||||
memset(next_lsf.dst, 0xFF, 6*sizeof(uint8_t));
|
||||
|
||||
//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 == 2) //AES ENC, 3200 voice
|
||||
{
|
||||
next_lsf.type[0] = 0x03;
|
||||
next_lsf.type[1] = 0x95;
|
||||
}
|
||||
else if (encryption == 1) //Scrambler ENC, 3200 Voice
|
||||
{
|
||||
next_lsf.type[0] = 0x03;
|
||||
next_lsf.type[1] = 0xCD;
|
||||
}
|
||||
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 = 0;
|
||||
|
||||
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=1;
|
||||
}
|
||||
|
||||
//AES
|
||||
if(encryption==2)
|
||||
{
|
||||
memcpy(&(next_lsf.meta), iv, 14);
|
||||
iv[14] = (fn >> 8) & 0x7F;
|
||||
iv[15] = (fn >> 0) & 0xFF;
|
||||
aes_ctr_bytewise_payload_crypt(iv, key, data, aes_type);
|
||||
}
|
||||
|
||||
//Scrambler
|
||||
else if (encryption == 1)
|
||||
{
|
||||
scrambler_sequence_generator();
|
||||
for(uint8_t i=0; i<16; i++)
|
||||
{
|
||||
data[i] ^= scr_bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(!finished)
|
||||
{
|
||||
|
@ -312,6 +669,19 @@ int main(int argc, char* argv[])
|
|||
for(uint8_t i=0; i<sizeof(sig); i++)
|
||||
fprintf(stderr, "%02X", sig[i]);
|
||||
fprintf(stderr, "\n");*/
|
||||
|
||||
if (debug_mode == 1)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
//send EOT frame
|
||||
|
@ -324,3 +694,27 @@ int main(int argc, char* argv[])
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//DEBUG:
|
||||
//Scrambler
|
||||
//encode debug with -- ./m17-coder-sym -D -k 123456 > scr.sym
|
||||
//decode debug with -- m17-fme -r -f scr.sym -v 1 -e 123456
|
||||
|
||||
//AES (with file import)
|
||||
//encode debug with -- ./m17-coder-sym -D -K sample_aes_key.txt> float.sym
|
||||
//decode debug with -- m17-fme -r -f float.sym -v 1 -J sample_aes_key.txt
|
||||
|
||||
//Signatures
|
||||
//encode debug with -- ./m17-coder-sym -D -s 69b07d7afe7f843e56ecbf536a49461dc5901c975d895bf1649cabff8f9b208b > float.sym
|
||||
//decode debug with -- cat ../m17-coder/float.sym | ./m17-decoder-sym -s c6c03dd11276aa917e7d83ae16d7f4fbf06f31be5869f9ae8004c329947dc4eeef0d9363653c8edf93e50912c6c515b40e0a8cbeea5e984dbc78e1993c8fbd5d
|
||||
//decode debug with -- m17-fme -r -f float.sym -v 1 -k ../m17-decoder/sample_pub_key.txt
|
||||
|
||||
//Signatures and AES
|
||||
//encode debug with -- ./m17-coder-sym -D -K sample_aes_key.txt -s 69b07d7afe7f843e56ecbf536a49461dc5901c975d895bf1649cabff8f9b208b > float.sym
|
||||
//decode debug with -- cat ../m17-coder/float.sym | ./m17-decoder-sym -s c6c03dd11276aa917e7d83ae16d7f4fbf06f31be5869f9ae8004c329947dc4eeef0d9363653c8edf93e50912c6c515b40e0a8cbeea5e984dbc78e1993c8fbd5d -K sample_aes_key.txt
|
||||
//decode debug with -- m17-fme -r -f float.sym -v 1 -k ../m17-decoder/sample_pub_key.txt -J sample_aes_key.txt
|
||||
|
||||
//Signatures and 24-bit Scrambler
|
||||
//encode debug with -- ./m17-coder-sym -D -k 543210 -s 69b07d7afe7f843e56ecbf536a49461dc5901c975d895bf1649cabff8f9b208b > float.sym
|
||||
//decode debug with -- cat ../m17-coder/float.sym | ./m17-decoder-sym -s c6c03dd11276aa917e7d83ae16d7f4fbf06f31be5869f9ae8004c329947dc4eeef0d9363653c8edf93e50912c6c515b40e0a8cbeea5e984dbc78e1993c8fbd5d -k 543210
|
||||
//decode debug with -- m17-fme -r -f float.sym -v 1 -k ../m17-decoder/sample_pub_key.txt -e 543210
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1234567890ABCDEF7777777777777777FEDCBA09876543218888888888888888
|
|
@ -1,5 +1,5 @@
|
|||
m17-decoder-sym: m17-decoder-sym.c
|
||||
gcc -O2 -Wall -Wextra m17-decoder-sym.c ../../micro-ecc/uECC.c -o m17-decoder-sym -lm -lm17
|
||||
gcc -O2 -Wall -Wextra m17-decoder-sym.c ../../micro-ecc/uECC.c ../../tinier-aes/aes.c -o m17-decoder-sym -lm -lm17
|
||||
|
||||
install:
|
||||
sudo cp m17-decoder-sym /usr/local/bin
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include "../../libm17/m17.h"
|
||||
//micro-ecc
|
||||
#include "../../micro-ecc/uECC.h"
|
||||
//tinier-aes
|
||||
#include "../../tinier-aes/aes.h"
|
||||
|
||||
//TODO: Load Signature Private and Public Keys from file
|
||||
|
||||
//settings
|
||||
uint8_t decode_callsigns=0;
|
||||
|
@ -42,6 +46,126 @@ uint8_t signed_str=0; //is the stream signed?
|
|||
uint8_t pub_key[64]={0}; //public key
|
||||
uint8_t sig[64]={0}; //ECDSA signature
|
||||
|
||||
//AES
|
||||
uint8_t encryption=0;
|
||||
int aes_type = 1; //1=AES128, 2=AES192, 3=AES256
|
||||
uint8_t key[32];
|
||||
uint8_t iv[16];
|
||||
time_t epoch = 1577836800L; //Jan 1, 2020, 00:00:00 UTC
|
||||
|
||||
//Scrambler
|
||||
uint8_t scr_bytes[16];
|
||||
uint8_t scrambler_pn[128];
|
||||
uint32_t scrambler_key=0; //keep set to initial value for seed calculation function
|
||||
uint32_t scrambler_seed=0;
|
||||
int8_t scrambler_subtype = -1;
|
||||
|
||||
//debug mode
|
||||
uint8_t debug_mode=0; //TODO: Remove lines looking at this
|
||||
|
||||
//this is generating a correct seed value based on the fn value,
|
||||
//ideally, we would only want to run this under poor signal, frame skips, etc
|
||||
//Note: Running this every frame will lag if high fn values (observed with test file)
|
||||
uint32_t scrambler_seed_calculation(int8_t subtype, uint32_t key, int fn)
|
||||
{
|
||||
int i;
|
||||
uint32_t lfsr, bit;
|
||||
|
||||
lfsr = key; bit = 0;
|
||||
for (i = 0; i < 128*fn; i++)
|
||||
{
|
||||
//get feedback bit with specified taps, depending on the subtype
|
||||
if (subtype == 0)
|
||||
bit = (lfsr >> 7) ^ (lfsr >> 5) ^ (lfsr >> 4) ^ (lfsr >> 3);
|
||||
else if (subtype == 1)
|
||||
bit = (lfsr >> 15) ^ (lfsr >> 14) ^ (lfsr >> 12) ^ (lfsr >> 3);
|
||||
else if (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
|
||||
lfsr = (lfsr << 1) | bit; //shift LFSR left once and OR bit onto LFSR's LSB
|
||||
lfsr &= 0xFFFFFF; //truncate lfsr to 24-bit
|
||||
|
||||
}
|
||||
|
||||
//truncate seed so subtype will continue to set properly on subsequent passes
|
||||
if (scrambler_subtype == 0) scrambler_seed &= 0xFF;
|
||||
if (scrambler_subtype == 1) scrambler_seed &= 0xFFFF;
|
||||
if (scrambler_subtype == 2) scrambler_seed &= 0xFFFFFF;
|
||||
else scrambler_seed &= 0xFF;
|
||||
|
||||
//debug
|
||||
//fprintf (stderr, "\nScrambler Key: 0x%06X; Seed: 0x%06X; Subtype: %02d; FN: %05d; ", key, lfsr, subtype, fn);
|
||||
|
||||
return lfsr;
|
||||
}
|
||||
|
||||
//scrambler pn sequence generation
|
||||
void 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_mode > 1)
|
||||
{
|
||||
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;
|
||||
if (scrambler_subtype == 1) scrambler_seed &= 0xFFFF;
|
||||
if (scrambler_subtype == 2) scrambler_seed &= 0xFFFFFF;
|
||||
else scrambler_seed &= 0xFF;
|
||||
|
||||
if (debug_mode > 1)
|
||||
{
|
||||
//debug packed bytes
|
||||
for (i = 0; i < 16; i++)
|
||||
fprintf (stderr, " %02X", scr_bytes[i]);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n");
|
||||
|
@ -51,6 +175,8 @@ void usage(void)
|
|||
fprintf(stderr, "-l - Display LSF CRC checks,\n");
|
||||
fprintf(stderr, "-d - Set syncword detection threshold (decimal value),\n");
|
||||
fprintf(stderr, "-s - Public key for ECDSA signature, 64 bytes (-s [hex_string|key_file]),\n");
|
||||
fprintf(stderr, "-K - AES encryption key (-K [hex_string|text_file]),\n");
|
||||
fprintf(stderr, "-k - Scrambler encryption seed value (-k [hex_string]),\n");
|
||||
fprintf(stderr, "-h - help / print usage\n");
|
||||
}
|
||||
|
||||
|
@ -161,6 +287,121 @@ int main(int argc, char* argv[])
|
|||
|
||||
i++;
|
||||
}
|
||||
|
||||
//Woj: There is a bug in loading keys this way, I think
|
||||
// it is to do with how scannign args is different here than in the encoder?
|
||||
//when loading by file, the key is shifted by one char
|
||||
//when loading the hex value, though, it works fine.
|
||||
if(argv[i][1]=='K') //-K - AES Encryption
|
||||
{
|
||||
if(strstr(argv[i+1], ".")) //if the next arg contains a dot - read key from a text file
|
||||
{
|
||||
char fname[128]={'\0'}; //output file
|
||||
if(strlen(&argv[i+1][0])>0)
|
||||
memcpy(fname, &argv[i+1][0], strlen(argv[i+1]));
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid filename. Exiting...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* fp;
|
||||
char source_str[64];
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if(!fp)
|
||||
{
|
||||
fprintf(stderr, "Failed to load file %s.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//size check
|
||||
size_t len = fread(source_str, 1, 64, fp); //TODO: check length
|
||||
fclose(fp);
|
||||
|
||||
if(len==256/4)
|
||||
fprintf(stderr, "AES256");
|
||||
else if(len==192/4)
|
||||
fprintf(stderr, "AES192");
|
||||
else if(len==128/4)
|
||||
fprintf(stderr, "AES128");
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid key length.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_raw_key_string(key, source_str);
|
||||
|
||||
fprintf(stderr, " key:");
|
||||
for(uint8_t i=0; i<len/2; i++)
|
||||
{
|
||||
if(i==16)
|
||||
fprintf(stderr, "\n ");
|
||||
fprintf(stderr, " %02X", key[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
//size check
|
||||
size_t len = strlen(argv[i+1]);
|
||||
|
||||
if(len==256/4)
|
||||
fprintf(stderr, "AES256");
|
||||
else if(len==192/4)
|
||||
fprintf(stderr, "AES192");
|
||||
else if(len==128/4)
|
||||
fprintf(stderr, "AES128");
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid key length.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_raw_key_string(key, argv[i+1]);
|
||||
|
||||
fprintf(stderr, " key:");
|
||||
for(uint8_t i=0; i<len/2; i++)
|
||||
{
|
||||
if(i==16)
|
||||
fprintf(stderr, "\n ");
|
||||
fprintf(stderr, " %02X", key[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
encryption=2; //AES key was passed
|
||||
}
|
||||
if(argv[i][1]=='k') //-k - Scrambler Encryption
|
||||
{
|
||||
//length check
|
||||
uint8_t length=strlen(argv[i+1]);
|
||||
if(length==0 || length>24/4) //24-bit is the largest seed value
|
||||
{
|
||||
fprintf(stderr, "Invalid key length.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_raw_key_string(key, argv[i+1]);
|
||||
scrambler_key = (key[0] << 16) | (key[1] << 8) | (key[2] << 0);
|
||||
|
||||
if(length<=2)
|
||||
{
|
||||
scrambler_key = scrambler_key >> 16;
|
||||
fprintf(stderr, "Scrambler key: 0x%02X (8-bit)\n", scrambler_key);
|
||||
}
|
||||
else if(length<=4)
|
||||
{
|
||||
scrambler_key = scrambler_key >> 8;
|
||||
fprintf(stderr, "Scrambler key: 0x%04X (16-bit)\n", scrambler_key);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Scrambler key: 0x%06X (24-bit)\n", scrambler_key);
|
||||
|
||||
encryption=1; //Scrambler key was passed
|
||||
scrambler_seed = scrambler_key; //set initial seed value to key value
|
||||
}
|
||||
|
||||
if(!strcmp(argv[i], "-l"))
|
||||
{
|
||||
|
@ -250,6 +491,44 @@ int main(int argc, char* argv[])
|
|||
uint16_t type=(uint16_t)lsf[12]*0x100+lsf[13]; //big-endian
|
||||
signed_str=(type>>11)&1;
|
||||
|
||||
///if the stream is signed (process before decryption)
|
||||
if(signed_str && fn<0x7FFC)
|
||||
{
|
||||
if(fn==0)
|
||||
memset(digest, 0, sizeof(digest));
|
||||
|
||||
for(uint8_t i=0; i<sizeof(digest); i++)
|
||||
digest[i]^=frame_data[3+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;
|
||||
}
|
||||
|
||||
//NOTE: Don't attempt decryption when a signed stream is >= 0x7FFC
|
||||
//The Signature is not encrypted
|
||||
|
||||
//AES
|
||||
if (encryption == 2 && fn<0x7FFC)
|
||||
{
|
||||
memcpy(iv, lsf+14, 14);
|
||||
iv[14] = frame_data[1] & 0x7F;
|
||||
iv[15] = frame_data[2] & 0xFF;
|
||||
aes_ctr_bytewise_payload_crypt(iv, key, frame_data+3, aes_type);
|
||||
}
|
||||
|
||||
//Scrambler
|
||||
if (encryption == 1 && fn<0x7FFC)
|
||||
{
|
||||
if ((fn % 0x8000)!=expected_next_fn) //frame skip, etc
|
||||
scrambler_seed = scrambler_seed_calculation(scrambler_subtype, scrambler_key, fn&0x7FFF);
|
||||
scrambler_sequence_generator();
|
||||
for(uint8_t i=0; i<16; i++)
|
||||
{
|
||||
frame_data[i+3] ^= scr_bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
//dump data - first byte is empty
|
||||
printf("FN: %04X PLD: ", fn);
|
||||
for(uint8_t i=3; i<19; i++)
|
||||
|
@ -264,20 +543,6 @@ int main(int argc, char* argv[])
|
|||
//send codec2 stream to stdout
|
||||
//fwrite(&frame_data[3], 16, 1, stdout);
|
||||
|
||||
//if the stream is signed
|
||||
if(signed_str && fn<0x7FFC)
|
||||
{
|
||||
if(fn==0)
|
||||
memset(digest, 0, sizeof(digest));
|
||||
|
||||
for(uint8_t i=0; i<sizeof(digest); i++)
|
||||
digest[i]^=frame_data[3+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;
|
||||
}
|
||||
|
||||
//extract LICH
|
||||
for(uint16_t i=0; i<96; i++)
|
||||
{
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1234567890ABCDEF7777777777777777FEDCBA09876543218888888888888888
|
|
@ -207,10 +207,10 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
uint16_t p_len=strlen((const char*)packet_data);
|
||||
uint16_t p_crc=CRC_M17(packet_data, p_len+1);
|
||||
fprintf(stderr, "Data CRC: rx=%02X%02X calc=%04X\n ", packet_data[p_len+1], packet_data[p_len+2], p_crc);
|
||||
fprintf(stderr, "Data CRC: rx=%02X%02X calc=%04X\n", packet_data[p_len+1], packet_data[p_len+2], p_crc);
|
||||
if(p_crc==(uint16_t)packet_data[p_len+1]*256+(uint16_t)packet_data[p_len+2])
|
||||
{
|
||||
fprintf(stderr, "%s\n", &packet_data[1]);
|
||||
fprintf(stderr, "SMS: %s\n", &packet_data[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,10 +218,12 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
if(!text_only)
|
||||
{
|
||||
fprintf(stderr, "PKT: ");
|
||||
for(uint16_t i=0; i<last_fn*25+rx_fn; i++)
|
||||
fprintf(stderr, "PKT:");
|
||||
for(uint16_t i=0; i<(last_fn+1)*25+rx_fn; i++)
|
||||
{
|
||||
fprintf(stderr, "%02X", packet_data[i]);
|
||||
if ( (i != 0) && ((i%25) == 0) )
|
||||
fprintf(stderr, "\n ");
|
||||
fprintf(stderr, " %02X", packet_data[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
|
|
@ -40,6 +40,14 @@ uint8_t out_type=0; //output file type -
|
|||
// 4 - S16-LE RRC filtered wav file
|
||||
// 5 - float symbol output for m17-packet-decode
|
||||
|
||||
|
||||
uint8_t std_encode = 1; //User Data is pre-encoded and read in over stdin, and not a switch string
|
||||
uint8_t sms_encode = 0; //User Supplied Data is an SMS Text message, encode as such
|
||||
uint8_t raw_encode = 0; //User Supplied Data is a string of hex octets, encode as such
|
||||
|
||||
char text[800] = "Default SMS Text message"; //SMS Text to Encode, default string.
|
||||
uint8_t raw[800]; //raw data that is converted from a string comprised of hex octets
|
||||
|
||||
//type - 0 - preamble before LSF (standard)
|
||||
//type - 1 - preamble before BERT transmission
|
||||
void fill_preamble(float* out, const uint8_t type)
|
||||
|
@ -87,12 +95,57 @@ void fill_data(float* out, uint16_t* cnt, const uint8_t* in)
|
|||
}
|
||||
}
|
||||
|
||||
//convert a user string (as hex octets) into a uint8_t array for raw packet encoding
|
||||
void parse_raw_user_string (char * input)
|
||||
{
|
||||
//since we want this as octets, get strlen value, then divide by two
|
||||
uint16_t len = strlen((const char*)input);
|
||||
|
||||
//if zero is returned, just do two
|
||||
if (len == 0) len = 2;
|
||||
|
||||
//if odd number, then user didn't pass complete octets, but just add one to len value to make it even
|
||||
if (len&1) len++;
|
||||
|
||||
//divide by two to get octet len
|
||||
len /= 2;
|
||||
|
||||
//sanity check, maximum strlen should not exceed 798 for a full encode
|
||||
if (len > 797) len = 797;
|
||||
|
||||
//set num_bytes to len + 1
|
||||
num_bytes = len + 0; //doing 0 instead, let user pass an extra 00 on the end if they want it there
|
||||
|
||||
char octet_char[3];
|
||||
octet_char[2] = 0;
|
||||
uint16_t k = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
//debug
|
||||
fprintf (stderr, "\nRaw Len: %d; Raw Octets:", len);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
strncpy (octet_char, input+k, 2);
|
||||
octet_char[2] = 0;
|
||||
sscanf (octet_char, "%hhX", &raw[i]);
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " (%s)", octet_char);
|
||||
fprintf (stderr, " %02X", raw[i]);
|
||||
|
||||
k += 2;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
//main routine
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
//scan command line options for input data
|
||||
//TODO: support for strings with spaces, the code below is NOT foolproof!
|
||||
//the user has to provide a minimum of 2 parameters: number of bytes and output filename
|
||||
//WIP: support for text strings with spaces and raw hex octet strings (still NOT foolproof)
|
||||
//the user has to provide a minimum of 2 parameters: input string or num_bytes, output type, and output filename
|
||||
if(argc>=4)
|
||||
{
|
||||
for(uint8_t i=1; i<argc; i++)
|
||||
|
@ -139,6 +192,28 @@ int main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
else if(argv[i][1]=='T') //-T - User Text String
|
||||
{
|
||||
if(strlen(&argv[i+1][0])>0)
|
||||
{
|
||||
memset(text, 0, 800*sizeof(char));
|
||||
memcpy(text, &argv[i+1][0], strlen(argv[i+1]));
|
||||
std_encode = 0;
|
||||
sms_encode = 1;
|
||||
raw_encode = 0;
|
||||
}
|
||||
}
|
||||
else if(argv[i][1]=='R') //-R - Raw Octets
|
||||
{
|
||||
if(strlen(&argv[i+1][0])>0)
|
||||
{
|
||||
memset (raw, 0, sizeof(raw));
|
||||
parse_raw_user_string (argv[i+1]);
|
||||
std_encode = 0;
|
||||
sms_encode = 0;
|
||||
raw_encode = 1;
|
||||
}
|
||||
}
|
||||
else if(argv[i][1]=='o') //-o - output filename
|
||||
{
|
||||
if(strlen(&argv[i+1][0])>0)
|
||||
|
@ -187,7 +262,9 @@ int main(int argc, char* argv[])
|
|||
fprintf(stderr, "-S - source callsign (uppercase alphanumeric string) max. 9 characters,\n");
|
||||
fprintf(stderr, "-D - destination callsign (uppercase alphanumeric string) or ALL for broadcast,\n");
|
||||
fprintf(stderr, "-C - Channel Access Number (0..15, default - 0),\n");
|
||||
fprintf(stderr, "-n - number of bytes (1 to 798),\n");
|
||||
fprintf(stderr, "-T - SMS Text Message (example: -T 'Hello World! This is a text message'),\n");
|
||||
fprintf(stderr, "-R - Raw Hex Octets (example: -R 010203040506070809),\n");
|
||||
fprintf(stderr, "-n - number of bytes, only when pre-encoded data passed over stdin (1 to 798),\n");
|
||||
fprintf(stderr, "-o - output file path/name,\n");
|
||||
fprintf(stderr, "Output formats:\n");
|
||||
//fprintf(stderr, "-x - binary output (M17 baseband as a packed bitstream),\n");
|
||||
|
@ -199,13 +276,8 @@ int main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
//assert number of bytes and filename
|
||||
if(num_bytes==0)
|
||||
{
|
||||
fprintf(stderr, "Number of bytes not set. Exiting...\n");
|
||||
return -1;
|
||||
}
|
||||
else if(strlen((const char*)fname)==0)
|
||||
//assert filename and not binary output
|
||||
if(strlen((const char*)fname)==0)
|
||||
{
|
||||
fprintf(stderr, "Filename not specified. Exiting...\n");
|
||||
return -1;
|
||||
|
@ -218,12 +290,43 @@ int main(int argc, char* argv[])
|
|||
|
||||
//obtain data and append with CRC
|
||||
memset(full_packet_data, 0, 32*25);
|
||||
if(fread(full_packet_data, num_bytes, 1, stdin)<1)
|
||||
|
||||
//SMS Encode (-T) ./m17-packet-encode -f -o float.sym -T 'This is a simple SMS text message sent over M17 Packet Data.'
|
||||
if (sms_encode == 1)
|
||||
{
|
||||
fprintf(stderr, "Packet data too short. Exiting...\n");
|
||||
return -1;
|
||||
num_bytes = strlen((const char*)text); //No need to check for zero return, since the default text string is supplied
|
||||
if (num_bytes > 796) num_bytes = 796; //not 798 because we have to manually add the 0x05 protocol byte and 0x00 terminator
|
||||
full_packet_data[0] = 0x05; //SMS Protocol
|
||||
memcpy (full_packet_data+1, text, num_bytes);
|
||||
num_bytes+= 2; //add one for terminating byte and 1 for strlen fix
|
||||
fprintf (stderr, "SMS: %s\n", full_packet_data+1);
|
||||
}
|
||||
|
||||
|
||||
//RAW Encode (-R) ./m17-packet-encode -f -o float.sym -R 5B69001E135152397C0A0000005A45
|
||||
else if (raw_encode == 1)
|
||||
{
|
||||
memcpy (full_packet_data, raw, num_bytes);
|
||||
}
|
||||
|
||||
//Old Method pre-encoded data over stdin // echo -en "\x05Testing M17 packet mode.\x00" | ./m17-packet-encode -S N0CALL -D AB1CDE -C 7 -n 26 -f -o float.sym
|
||||
else if (std_encode == 1)
|
||||
{
|
||||
//assert number of bytes
|
||||
if(num_bytes==0)
|
||||
{
|
||||
fprintf(stderr, "Number of bytes not set. Exiting...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(fread(full_packet_data, num_bytes, 1, stdin)<1)
|
||||
{
|
||||
fprintf(stderr, "Packet data too short. Exiting...\n");
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "SMS: %s\n", full_packet_data+1);
|
||||
//
|
||||
}
|
||||
|
||||
uint16_t packet_crc=CRC_M17(full_packet_data, num_bytes);
|
||||
full_packet_data[num_bytes] =packet_crc>>8;
|
||||
full_packet_data[num_bytes+1]=packet_crc&0xFF;
|
||||
|
@ -244,8 +347,7 @@ int main(int argc, char* argv[])
|
|||
#else
|
||||
fprintf(stderr, "DST: %s\t%012lX\nSRC: %s\t%012lX\n", dst_raw, dst_encoded, src_raw, src_encoded);
|
||||
#endif
|
||||
//fprintf(stderr, "DST: %02X %02X %02X %02X %02X %02X\n", lsf.dst[0], lsf.dst[1], lsf.dst[2], lsf.dst[3], lsf.dst[4], lsf.dst[5]);
|
||||
//fprintf(stderr, "SRC: %02X %02X %02X %02X %02X %02X\n", lsf.src[0], lsf.src[1], lsf.src[2], lsf.src[3], lsf.src[4], lsf.src[5]);
|
||||
fprintf(stderr, "CAN: %02d\n", can);
|
||||
fprintf(stderr, "Data CRC:\t%04hX\n", packet_crc);
|
||||
type=((uint16_t)0x01<<1)|((uint16_t)can<<7); //packet mode, content: data
|
||||
lsf.type[0]=(uint16_t)type>>8;
|
||||
|
@ -296,7 +398,10 @@ int main(int argc, char* argv[])
|
|||
//send packet frame syncword
|
||||
fill_syncword(full_packet, &pkt_sym_cnt, SYNC_PKT);
|
||||
|
||||
if(num_bytes>=25)
|
||||
//the following examples produce exactly 25 bytes, which exactly one frame, but >= meant this would never produce a final frame with EOT bit set
|
||||
//echo -en "\x05Testing M17 packet mo\x00" | ./m17-packet-encode -S N0CALL -D ALL -C 10 -n 23 -o float.sym -f
|
||||
//./m17-packet-encode -S N0CALL -D ALL -C 10 -o float.sym -f -T 'this is a simple text'
|
||||
if(num_bytes>25) //fix for frames that, with terminating byte and crc, land exactly on 25 bytes (or %25==0)
|
||||
{
|
||||
memcpy(pkt_chunk, &full_packet_data[pkt_cnt*25], 25);
|
||||
pkt_chunk[25]=pkt_cnt<<2;
|
||||
|
@ -368,16 +473,16 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
num_bytes=tmp; //bring back the num_bytes value
|
||||
|
||||
fprintf (stderr, "FULL: ");
|
||||
for(uint8_t i=0; i<tmp; i++)
|
||||
fprintf (stderr, "PKT:");
|
||||
for(uint8_t i=0; i<pkt_cnt*25; i++)
|
||||
{
|
||||
fprintf (stderr, "%02X", full_packet_data[i]);
|
||||
if ( (i != 0) && ((i%25) == 0) )
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
fprintf (stderr, " %02X", full_packet_data[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, " SMS: %s\n", full_packet_data);
|
||||
|
||||
//send EOT
|
||||
for(uint8_t i=0; i<SYM_PER_FRA/SYM_PER_SWD; i++) //192/8=24
|
||||
fill_syncword(full_packet, &pkt_sym_cnt, EOT_MRKR);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f602803fde808f8b22a1c724857a3928c91169d3
|
Ładowanie…
Reference in New Issue