Merge pull request #33 from lwvmobile/auth_plus_crypto

Manually Merge Crypto Branch in Auth Branch
pull/35/head
Wojciech Kaczmarski 2024-06-23 10:09:50 +02:00 zatwierdzone przez GitHub
commit be13f76803
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
12 zmienionych plików z 898 dodań i 92 usunięć

3
.gitignore vendored
Wyświetl plik

@ -9,4 +9,5 @@
*.wav
*.bin
*.sym
*.patch
*.patch
*.txt

3
.gitmodules vendored
Wyświetl plik

@ -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
Wyświetl plik

@ -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
```

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1 @@
1234567890ABCDEF7777777777777777FEDCBA09876543218888888888888888

Wyświetl plik

@ -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

Wyświetl plik

@ -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++)
{

Wyświetl plik

@ -0,0 +1 @@
1234567890ABCDEF7777777777777777FEDCBA09876543218888888888888888

Wyświetl plik

@ -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");
}

Wyświetl plik

@ -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);

1
tinier-aes 160000

@ -0,0 +1 @@
Subproject commit f602803fde808f8b22a1c724857a3928c91169d3