mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
26 Commits
rtl_overha
...
20251214
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abf28593b1 | ||
|
|
bc4aeff164 | ||
|
|
632041a44a | ||
|
|
f1cd83e924 | ||
|
|
50bf004427 | ||
|
|
85a6372c2e | ||
|
|
eb76ea2039 | ||
|
|
14edf325bc | ||
|
|
e11ed353b8 | ||
|
|
f8521fda99 | ||
|
|
fa47d0321b | ||
|
|
095d982b62 | ||
|
|
0060378321 | ||
|
|
8ea6415424 | ||
|
|
eb24239c51 | ||
|
|
ac1c658870 | ||
|
|
cf032ab955 | ||
|
|
2d04878506 | ||
|
|
748bb5b191 | ||
|
|
f3b89f1c51 | ||
|
|
b2d388a210 | ||
|
|
c883e2bf0b | ||
|
|
f8ca0a8e08 | ||
|
|
99b1fd2fe2 | ||
|
|
b0a46a541d | ||
|
|
3aabd85604 |
@@ -61,6 +61,10 @@ if [ "$RELEASE" = "y" ]; then
|
||||
#start copying things to the lib folder
|
||||
cp -r /lib/pulseaudio/ dsd-fme-portable/lib/
|
||||
|
||||
#support for LAPACK, BLAS, and FFTW3 (SIMD math libraries and dependencies)
|
||||
cp /lib/lapack/* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggfortran* dsd-fme-portable/dsd-fme/
|
||||
|
||||
#start copying things into the dsd-fme folder
|
||||
cp dsd-fme/build/dsd-fme.exe dsd-fme-portable/dsd-fme/
|
||||
cp -r dsd-fme/examples dsd-fme-portable/dsd-fme/
|
||||
@@ -70,7 +74,7 @@ if [ "$RELEASE" = "y" ]; then
|
||||
cp .profile dsd-fme-portable/dsd-fme/
|
||||
|
||||
#move (cut) the bat files to the portable folder root and delete the other ones so users won't get confused
|
||||
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/start-dsd-fme.bat dsd-fme-portable/
|
||||
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/*.bat dsd-fme-portable/
|
||||
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/example_options.txt dsd-fme-portable/
|
||||
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/complete_usage_options.txt dsd-fme-portable/
|
||||
rm -rf dsd-fme-portable/dsd-fme/examples/cygwin_bat
|
||||
@@ -128,7 +132,6 @@ if [ "$RELEASE" = "y" ]; then
|
||||
cp /bin/cygdbus* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygedit* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygexpat* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygfam* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygfdisk* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygffi* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygfftw3_threads* dsd-fme-portable/dsd-fme/
|
||||
@@ -152,7 +155,6 @@ if [ "$RELEASE" = "y" ]; then
|
||||
cp /bin/cyggomp* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggpg-error* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggpgme* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggsasl* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggsm* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggssapi_krb5* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cyggthread* dsd-fme-portable/dsd-fme/
|
||||
@@ -179,7 +181,6 @@ if [ "$RELEASE" = "y" ]; then
|
||||
cp /bin/cygncurses* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygnettle* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygnghttp* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygntlm* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygobjc* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygogg* dsd-fme-portable/dsd-fme/
|
||||
cp /bin/cygopus* dsd-fme-portable/dsd-fme/
|
||||
|
||||
@@ -25,6 +25,10 @@ if [ "$ANSWER" = "y" ]; then
|
||||
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||
tar xjf itpp-latest.tar.bz2
|
||||
cd itpp-4.3.1/
|
||||
#newer Cygwin has Cmake 4.1.3 (or newer) so we need to replace the line with cmake_minimum_required to a newer version
|
||||
#this doesn't seem to break anything, its just that cmake will refuse to run properly without a newer min version in it
|
||||
#I'm just going to use the version that is used for most all my other cmake projects, seems to still be okay with new cmake
|
||||
sed -i '/^cmake_minimum_required *( *VERSION *2\.8\.6 *)$/c\cmake_minimum_required(VERSION 3.10.2)' CMakeLists.txt
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
|
||||
@@ -135,7 +135,7 @@ Open Windows PowerShell (not Command Prompt) and copy and paste all of this in a
|
||||
|
||||
```
|
||||
Invoke-WebRequest https://cygwin.com/setup-x86_64.exe -OutFile setup-x86_64.exe
|
||||
.\setup-x86_64.exe --packages nano,libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,zip,unzip,wget,gcc-g++,libsndfile-devel
|
||||
.\setup-x86_64.exe --packages nano,libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,zip,unzip,wget,gcc-g++,libsndfile-devel,libopenblas,liblapack-devel,libfftw3-devel
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Build Version: AW 2025-182-g24c1dd9
|
||||
Build Version: AW 2025-209-g14edf32
|
||||
MBElib Version: 1.3.4
|
||||
CODEC2 Support Enabled
|
||||
|
||||
@@ -23,8 +23,6 @@ Input/Output options:
|
||||
rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)
|
||||
tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)
|
||||
tcp:192.168.7.5:7355 for custom address and port
|
||||
m17udp for M17 UDP/IP socket bind input (default host 127.0.0.1; default port 17000)
|
||||
m17udp:192.168.7.8:17001 for M17 UDP/IP bind input (Binding Address and Port
|
||||
filename.bin for OP25/FME capture bin files
|
||||
filename.wav for 48K/1 wav files (SDR++, GQRX)
|
||||
filename.wav -s 96000 for 96K/1 wav files (DSDPlus)
|
||||
@@ -37,8 +35,6 @@ Input/Output options:
|
||||
null for no audio output
|
||||
udp for UDP socket blaster output (default host 127.0.0.1; default port 23456)
|
||||
udp:192.168.7.8:23470 for UDP socket blaster output (Target Address and Port
|
||||
m17udp for M17 UDP/IP socket blaster output (default host 127.0.0.1; default port 17000)
|
||||
m17udp:192.168.7.8:17001 for M17 UDP/IP blaster output (Target Address and Port
|
||||
-d <dir> Create mbe data files, use this directory (TDMA version is experimental)
|
||||
-r <files> Read/Play saved mbe data from file(s)
|
||||
-g <float> Audio Digital Output Gain (Default: 0 = Auto; )
|
||||
@@ -81,26 +77,6 @@ RTL-SDR options:
|
||||
Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T
|
||||
Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2
|
||||
|
||||
Encoder options:
|
||||
-fZ M17 Stream Voice Encoder
|
||||
Example: dsd-fme -fZ -M M17:9:DSD-FME:LWVMOBILE -i pulse -6 m17signal.wav -8 -N 2> m17encoderlog.txt
|
||||
Run M17 Encoding, listening to pulse audio server, with internal decode/playback and output to 48k/1 wav file
|
||||
|
||||
Example: dsd-fme -fZ -M M17:9:DSD-FME:LWVMOBILE -i tcp -o pulse -8 -N 2> m17encoderlog.txt
|
||||
Run M17 Encoding, listening to default tcp input, without internal decode/playback and output to 48k/1 analog output device
|
||||
|
||||
-fP M17 Packet Encoder
|
||||
Example: dsd-fme -fP -M M17:9:DSD-FME:LWVMOBILE -6 m17pkt.wav -8 -S 'Hello World'
|
||||
|
||||
-fB M17 BERT Encoder
|
||||
Example: dsd-fme -fB -M M17:9:DSD-FME:LWVMOBILE -6 m17bert.wav -8
|
||||
|
||||
-M M17 Encoding User Configuration String: M17:CAN:SRC:DST:INPUT_RATE:VOX (see examples above).
|
||||
CAN 1-15; SRC and DST have to be no more than 9 UPPER base40 characters.
|
||||
BASE40: ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.'
|
||||
Input Rate Default is 48000; Use Multiples of 8000 up to 48000.
|
||||
VOX Enabled on 1; (Default = 0)
|
||||
Values not entered into the M17: string are set to default values.
|
||||
Decoder options:
|
||||
-fa Auto Detection
|
||||
-fA Passive Analog Audio Monitor
|
||||
@@ -112,7 +88,6 @@ Decoder options:
|
||||
-fx Decode only X2-TDMA
|
||||
-fy Decode only YSF
|
||||
-fz Decode only M17*
|
||||
-fU Decode only M17 UDP/IP Frame***
|
||||
-fi Decode only NXDN48* (6.25 kHz) / IDAS*
|
||||
-fn Decode only NXDN96* (12.5 kHz)
|
||||
-fp Decode only ProVoice*
|
||||
@@ -128,15 +103,15 @@ Decoder options:
|
||||
-xx Expect non-inverted X2-TDMA signal
|
||||
-xr Expect inverted DMR signal
|
||||
-xd Expect inverted ICOM dPMR signal
|
||||
-xz Expect inverted M17 signal
|
||||
|
||||
* denotes frame types that cannot be auto-detected.
|
||||
** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.
|
||||
*** configure UDP Input with -i m17:127.0.0.1:17000
|
||||
|
||||
Advanced Decoder options:
|
||||
-X <hex> Manually Set P2 Parameters (WACN, SYSID, CC/NAC)
|
||||
(-X BEE00ABC123)
|
||||
-_ <dec> Manually Set NXDN PN95 Dibit Scrambler Seed (1-511)
|
||||
(-* 261)
|
||||
-D <dec> Manually Set TIII DMR Location Area n bit len (0-10)(10 max)
|
||||
(Value defaults to max n bit value for site model size)
|
||||
(Setting 0 will show full Site ID, no area/subarea)
|
||||
@@ -150,10 +125,9 @@ Advanced Decoder options:
|
||||
Use this feature to allow MAC_SIGNAL even if CRC errors.
|
||||
-F Relax DMR RAS/CRC CSBK/DATA Pass/Fail
|
||||
Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal
|
||||
-F Relax M17 LSF/PKT CRC Error Checking
|
||||
|
||||
-b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)
|
||||
(NOTE: This used to be the 'K' option!
|
||||
(NOTE: This used to be the 'K' option!)
|
||||
|
||||
-H <hex> Manually Enter Hytera 10/32/64 Char Basic Privacy Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
@@ -161,7 +135,7 @@ Advanced Decoder options:
|
||||
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||
|
||||
-H <hex> Manually Enter AES-128 or AES-256 Hex Key (see example below)
|
||||
-H <hex> Manually Enter AES-128, AES-256, or Kirisun-256 Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||
@@ -172,14 +146,28 @@ Advanced Decoder options:
|
||||
|
||||
-2 <hex> Manually Enter and Enforce TYT 16-bit BP Key Value (DMR) (Hex Value)
|
||||
|
||||
-! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) AP Hex Key (see example below)
|
||||
-! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) 128 or 256 bit AP Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
-! '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
-! '1111111111111111 1111111111111111 1111111111111111 1111111111111111'
|
||||
|
||||
-@ <hex> Manually Enter and Enforce Retevis Advanced Privacy (RC2) 128 or 256 bit AP Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
-@ '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
-@ '1122334455667788 99AABBCCDDEEFF11 1122334455667788 99AABBCCDDEEFF11'
|
||||
|
||||
-5 <hex> Manually Enter and Enforce TYT Enhanced Privacy (AES-128) EP Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
-5 '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
|
||||
-+ <hex> Manually Enter and Enforce Baofeng Advanced Privacy (PC5-128 or PC5-256) AP Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
-+ 'ABCDABCDABCDABCD ABDCDABCDABCDABC'
|
||||
-+ 'ABCDABCDABCDABCD ABDCDABCDABCDABC EF01EF01EF01EF01 EF01EF01EF01EF01'
|
||||
|
||||
-^ <hex> Manually Enter and Enforce Connect Systems 72-bit (9-byte) Extended Encryption Hex Key (see example below)
|
||||
-^ 3BBE782C0430008271
|
||||
|
||||
-9 <dec> Manually Enter and Enforce Kenwood 15-bit Scrambler Key Value (DMR) (Dec Value)
|
||||
|
||||
-A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value)
|
||||
@@ -191,6 +179,8 @@ Advanced Decoder options:
|
||||
-S 49:123456789ABC80
|
||||
For Example, enter 49-bit Keystream (MBP 70) as:
|
||||
-S 49:ED0AED4AED4AED4A
|
||||
For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:
|
||||
-S 49:11AA22BB33CC44
|
||||
|
||||
-k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.
|
||||
Only supports NXDN, DMR Basic Privacy (decimal value).
|
||||
@@ -203,6 +193,8 @@ Advanced Decoder options:
|
||||
|
||||
-0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)
|
||||
|
||||
-M <hex> Force Entered Alg ID Value over Missing PI header/LE Encryption Identifiers (DMR)
|
||||
|
||||
-3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst)
|
||||
Note: Disable this if false positives on Voice ENC occur.
|
||||
|
||||
@@ -228,4 +220,5 @@ Advanced Decoder options:
|
||||
-t <secs> Set Trunking or Scan Speed VC/sync loss hangtime in seconds. (default = 1 second)
|
||||
|
||||
Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.txt
|
||||
Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.txt
|
||||
Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.txt
|
||||
|
||||
|
||||
@@ -357,10 +357,6 @@ typedef struct
|
||||
int ssize;
|
||||
int msize;
|
||||
int playfiles;
|
||||
int m17encoder;
|
||||
int m17encoderbrt;
|
||||
int m17encoderpkt;
|
||||
int m17decoderip;
|
||||
int delay;
|
||||
int use_cosine_filter;
|
||||
int unmute_encrypted_p25;
|
||||
@@ -414,7 +410,6 @@ typedef struct
|
||||
short int aggressive_framesync;
|
||||
|
||||
int frame_m17;
|
||||
int inverted_m17;
|
||||
|
||||
FILE *symbolfile;
|
||||
int call_alert;
|
||||
@@ -431,12 +426,6 @@ typedef struct
|
||||
int udp_portno;
|
||||
char udp_hostname[1024];
|
||||
|
||||
//M17 UDP for IP frame output
|
||||
int m17_use_ip; //if enabled, open UDP and broadcast IP frame
|
||||
int m17_portno; //default is 17000
|
||||
int m17_udp_sock; //actual UDP socket for M17 to send to
|
||||
char m17_hostname[1024];
|
||||
|
||||
//tcp socket for SDR++, etc
|
||||
int tcp_sockfd;
|
||||
int tcp_portno;
|
||||
@@ -643,7 +632,7 @@ typedef struct
|
||||
unsigned long long int K2;
|
||||
unsigned long long int K3;
|
||||
unsigned long long int K4;
|
||||
int M;
|
||||
uint8_t forced_alg_id;
|
||||
int menuopen;
|
||||
|
||||
//AES Key Segments
|
||||
@@ -898,6 +887,7 @@ typedef struct
|
||||
uint8_t nxdn_sacch_frame_segcrc[4];
|
||||
uint8_t nxdn_alias_block_number;
|
||||
char nxdn_alias_block_segment[4][4][8];
|
||||
uint16_t nxdn_pn95_seed;
|
||||
|
||||
//site/srv/cch info
|
||||
char nxdn_location_category[14];
|
||||
@@ -952,15 +942,11 @@ typedef struct
|
||||
//M17 Storage
|
||||
uint8_t m17_lsf[360];
|
||||
uint8_t m17_pkt[850];
|
||||
uint8_t m17_pbc_ct; //pbc packet counter
|
||||
uint8_t m17_str_dt; //stream contents
|
||||
|
||||
unsigned long long int m17_dst;
|
||||
unsigned long long int m17_src;
|
||||
uint8_t m17_can; //can value that was decoded from signal
|
||||
int m17_can_en; //can value supplied to the encoding side
|
||||
int m17_rate; //sampling rate for audio input
|
||||
int m17_vox; //vox enabled via RMS value
|
||||
|
||||
char m17_dst_csd[20];
|
||||
char m17_src_csd[20];
|
||||
@@ -968,18 +954,22 @@ typedef struct
|
||||
char m17_src_str[50];
|
||||
char m17_dst_str[50];
|
||||
|
||||
uint8_t m17_meta[16]; //packed meta
|
||||
uint8_t m17_enc; //enc type
|
||||
uint8_t m17_enc_st; //scrambler or data subtye
|
||||
int m17encoder_tx; //if TX (encode + decode) M17 Stream is enabled
|
||||
int m17encoder_eot; //signal if we need to send the EOT frame
|
||||
uint8_t m17_meta[16]; //packed meta
|
||||
uint8_t m17_aes_iv[16]; //aes iv
|
||||
uint8_t m17_enc; //enc type
|
||||
uint8_t m17_enc_st; //scrambler or data subtye
|
||||
|
||||
char m17_text_string[1024];
|
||||
char m17_gnss_string[1024];
|
||||
char m17_data_string[1024];
|
||||
char m17_meta_string[1024];
|
||||
|
||||
float m17_viterbi_err;
|
||||
|
||||
//misc str storage
|
||||
char str50a[50];
|
||||
char str50b[50];
|
||||
char str50c[50];
|
||||
char m17dat[50]; //user supplied m17 data input string
|
||||
char m17sms[800]; //user supplied sms text string
|
||||
|
||||
//Codec2
|
||||
#ifdef USE_CODEC2
|
||||
@@ -991,6 +981,9 @@ typedef struct
|
||||
int tyt_ap;
|
||||
int tyt_bp;
|
||||
int tyt_ep;
|
||||
// retrevis rc2
|
||||
int retevis_ap;
|
||||
void *rc2_context;
|
||||
|
||||
//kenwood scrambler on DMR with forced application
|
||||
int ken_sc;
|
||||
@@ -998,6 +991,12 @@ typedef struct
|
||||
//anytone bp
|
||||
int any_bp;
|
||||
|
||||
//baofeng ap
|
||||
int baofeng_ap;
|
||||
|
||||
//connect systems ee
|
||||
int csi_ee;
|
||||
|
||||
//generic ks
|
||||
int straight_ks;
|
||||
int straight_mod;
|
||||
@@ -1014,13 +1013,6 @@ typedef struct
|
||||
//M17 Sync Patterns
|
||||
#define M17_LSF "11113313"
|
||||
#define M17_STR "33331131"
|
||||
//alternating with last symbol opposite of first symbol of LSF
|
||||
#define M17_PRE "31313131"
|
||||
#define M17_PIV "13131313"
|
||||
#define M17_PRE_LSF "3131313133331131" //Preamble + LSF
|
||||
#define M17_PIV_LSF "1313131311113313" //Preamble + LSF
|
||||
#define M17_BRT "31331111"
|
||||
#define M17_PKT "13113333"
|
||||
|
||||
#define FUSION_SYNC "31111311313113131131"
|
||||
#define INV_FUSION_SYNC "13333133131331313313"
|
||||
@@ -1244,13 +1236,6 @@ void processDSTAR_HD (dsd_opts * opts, dsd_state * state); //DSTAR Header
|
||||
void processDSTAR_SD (dsd_opts * opts, dsd_state * state, uint8_t * sd); //DSTAR Slow Data
|
||||
void processYSF(dsd_opts * opts, dsd_state * state); //YSF
|
||||
void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
|
||||
void processM17PKT(dsd_opts * opts, dsd_state * state); //M17 (PKT)
|
||||
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
|
||||
void processM17IPF(dsd_opts * opts, dsd_state * state); //M17 (IPF)
|
||||
void encodeM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR) encoder
|
||||
void encodeM17BRT(dsd_opts * opts, dsd_state * state); //M17 (BRT) encoder
|
||||
void encodeM17PKT(dsd_opts * opts, dsd_state * state); //M17 (PKT) encoder
|
||||
void decodeM17PKT(dsd_opts * opts, dsd_state * state, uint8_t * input, int len); //M17 (PKT) decoder
|
||||
void processP2(dsd_opts * opts, dsd_state * state); //P2
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block
|
||||
void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks)
|
||||
@@ -1278,7 +1263,7 @@ void ncursesClose ();
|
||||
|
||||
//new NXDN Functions start here!
|
||||
void nxdn_frame (dsd_opts * opts, dsd_state * state);
|
||||
void nxdn_descramble (uint8_t dibits[], int len);
|
||||
void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len);
|
||||
//nxdn deinterleaving/depuncturing functions
|
||||
void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
|
||||
void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
|
||||
@@ -1289,7 +1274,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
|
||||
//DCR Mode
|
||||
void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144], uint8_t lich);
|
||||
//MT and Voice
|
||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
||||
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
||||
@@ -1312,6 +1297,12 @@ void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsign
|
||||
void CNXDNConvolution_init();
|
||||
|
||||
//libM17 viterbi decoder
|
||||
|
||||
//libm17 magic soft decision based viterbi
|
||||
#define SYM_PER_PLD 184
|
||||
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD]);
|
||||
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2]);
|
||||
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2]);
|
||||
uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len);
|
||||
uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len);
|
||||
void viterbi_decode_bit(uint16_t s0, uint16_t s1, const size_t pos);
|
||||
@@ -1337,6 +1328,10 @@ void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message
|
||||
void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
//Type-D SCCH Message Decoder
|
||||
void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uint8_t direction);
|
||||
void NXDN_decode_VCALL_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
void NXDN_decode_ALIAS_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
uint32_t sjis_char_to_unicode(uint16_t sjis);
|
||||
int utf8_encode(int c, char *buf);
|
||||
|
||||
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
|
||||
|
||||
@@ -1609,9 +1604,6 @@ int udp_socket_connect(dsd_opts * opts, dsd_state * state);
|
||||
int udp_socket_connectA(dsd_opts * opts, dsd_state * state);
|
||||
void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
||||
void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
||||
int m17_socket_receiver(dsd_opts * opts, void * data);
|
||||
int udp_socket_connectM17(dsd_opts * opts, dsd_state * state);
|
||||
int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
||||
|
||||
//RC4 function prototypes
|
||||
void rc4_voice_decrypt (int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[]);
|
||||
@@ -1629,16 +1621,22 @@ void aes_cfb_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in,
|
||||
void aes_ctr_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type);
|
||||
void aes_ctr_bitwise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type);
|
||||
|
||||
//Tytera Encryption Modes
|
||||
//Tytera / Retevis / Anytone / Kenwood / Misc DMR Encryption Modes
|
||||
void tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int fnum);
|
||||
void tyt_ep_aes_keystream_creation(dsd_state * state, char * input);
|
||||
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input);
|
||||
|
||||
//Misc Other Encryption Modes
|
||||
void retevis_rc2_keystream_creation(dsd_state *state, char *input);
|
||||
void ken_dmr_scrambler_keystream_creation(dsd_state * state, char * input);
|
||||
void anytone_bp_keystream_creation(dsd_state * state, char * input);
|
||||
void baofeng_ap_pc5_keystream_creation(dsd_state *state, char *input);
|
||||
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24]);
|
||||
void straight_mod_xor_keystream_creation(dsd_state * state, char * input);
|
||||
|
||||
//Kirisun
|
||||
uint32_t kirisun_lfsr(unsigned long long int mi);
|
||||
void kirisun_adv_keystream_creation(dsd_state *state);
|
||||
void kirisun_uni_keystream_creation(dsd_state *state);
|
||||
|
||||
//Hytera Enhanced
|
||||
void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value);
|
||||
unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
|
||||
|
||||
147
include/pc5.h
Normal file
147
include/pc5.h
Normal file
@@ -0,0 +1,147 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef BAOFENG_AP
|
||||
#define BAOFENG_AP
|
||||
|
||||
#define nbround 254
|
||||
#define n1 264
|
||||
|
||||
#define UNUSEDPC5(x) ((void)x)
|
||||
|
||||
/* Structure holding all PC5 state variables */
|
||||
typedef struct {
|
||||
short bits[49], temp[49];
|
||||
uint8_t ptconvert;
|
||||
uint8_t convert[7];
|
||||
uint8_t perm[16][256];
|
||||
uint8_t new1[256];
|
||||
uint8_t array[49];
|
||||
uint8_t array2[49];
|
||||
uint8_t decal[nbround];
|
||||
uint8_t rngxor[nbround][3];
|
||||
uint8_t rngxor2[nbround][3];
|
||||
uint8_t rounds;
|
||||
uint8_t tab[256];
|
||||
uint8_t inv[256];
|
||||
uint8_t permut[3][3];
|
||||
uint64_t bb;
|
||||
uint64_t x;
|
||||
uint8_t tot[3];
|
||||
uint8_t l[2][3], r[2][3];
|
||||
uint8_t y, totb;
|
||||
uint32_t result;
|
||||
uint8_t xyz, count;
|
||||
uint8_t keys[16];
|
||||
unsigned char array_arc4[256];
|
||||
int i_arc4, j_arc4;
|
||||
int x1, x2, i;
|
||||
unsigned char h2[n1];
|
||||
unsigned char h1[n1*3];
|
||||
uint8_t numbers[25];
|
||||
} PC5Context;
|
||||
|
||||
/* Global context accessible from all .c files */
|
||||
extern PC5Context ctxpc5;
|
||||
|
||||
/* Public API */
|
||||
void create_keys_pc5(PC5Context *ctxpc5, unsigned char key1[], size_t size1);
|
||||
void pc5encrypt(PC5Context *ctxpc5);
|
||||
void pc5decrypt(PC5Context *ctxpc5);
|
||||
void binhexpc5(PC5Context *ctxpc5, short *z, int length);
|
||||
void hexbinpc5(PC5Context *ctxpc5, short *q, uint8_t w, uint8_t hex);
|
||||
static void u64_to_bytes_be_pc5(uint64_t val, unsigned char *out);
|
||||
|
||||
/* Encrypt a 49-bit frame using PC5 algorithm (original flow) */
|
||||
static void encrypt_frame_49_pc5(short frame_bits_in[49]) {
|
||||
// Only process first 24 bits for encryption, rest are XORed
|
||||
ctxpc5.ptconvert = 0;
|
||||
binhexpc5(&ctxpc5, frame_bits_in, 24);
|
||||
|
||||
uint8_t convert[6];
|
||||
|
||||
// Store first 3 bytes in convert
|
||||
for (int i = 0; i < 3; i++) convert[i] = ctxpc5.convert[i];
|
||||
|
||||
// Split each byte into two 4-bit nibbles
|
||||
ctxpc5.convert[0] = convert[0] >> 4;
|
||||
ctxpc5.convert[1] = convert[0] & 0xF;
|
||||
ctxpc5.convert[2] = convert[1] >> 4;
|
||||
ctxpc5.convert[3] = convert[1] & 0xF;
|
||||
ctxpc5.convert[4] = convert[2] >> 4;
|
||||
ctxpc5.convert[5] = convert[2] & 0xF;
|
||||
|
||||
pc5encrypt(&ctxpc5);
|
||||
|
||||
// Store encrypted nibbles back in convert
|
||||
for (int i = 0; i < 6; i++) convert[i] = ctxpc5.convert[i];
|
||||
|
||||
// Recombine nibbles into bytes
|
||||
ctxpc5.convert[0] = (convert[0] << 4) + convert[1];
|
||||
ctxpc5.convert[1] = (convert[2] << 4) + convert[3];
|
||||
ctxpc5.convert[2] = (convert[4] << 4) + convert[5];
|
||||
|
||||
// Convert back to bits for first 24 bits
|
||||
for (int q = 0; q < 3; q++) {
|
||||
uint8_t w = (uint8_t)(q * 8);
|
||||
hexbinpc5(&ctxpc5, frame_bits_in, w, ctxpc5.convert[q]);
|
||||
}
|
||||
|
||||
// XOR the remaining bits (positions 24 to 48)
|
||||
for (int i = 24; i < 49; i++) {
|
||||
frame_bits_in[i] = (short)(frame_bits_in[i] ^ ctxpc5.numbers[i - 24]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 49; i++) ctxpc5.bits[i] = frame_bits_in[i];
|
||||
}
|
||||
|
||||
/* Decrypt a 49-bit frame using PC5 algorithm (original flow) */
|
||||
static void decrypt_frame_49_pc5(short frame_bits_in[49]) {
|
||||
// XOR the remaining bits (positions 24 to 48) first
|
||||
for (int i = 24; i < 49; i++) {
|
||||
frame_bits_in[i] = (short)(frame_bits_in[i] ^ ctxpc5.numbers[i - 24]);
|
||||
}
|
||||
|
||||
ctxpc5.ptconvert = 0;
|
||||
binhexpc5(&ctxpc5, frame_bits_in, 24);
|
||||
|
||||
uint8_t convert[6];
|
||||
|
||||
// Store first 3 bytes in convert
|
||||
for (int i = 0; i < 3; i++) convert[i] = ctxpc5.convert[i];
|
||||
|
||||
// Split each byte into two 4-bit nibbles
|
||||
ctxpc5.convert[0] = convert[0] >> 4;
|
||||
ctxpc5.convert[1] = convert[0] & 0xF;
|
||||
ctxpc5.convert[2] = convert[1] >> 4;
|
||||
ctxpc5.convert[3] = convert[1] & 0xF;
|
||||
ctxpc5.convert[4] = convert[2] >> 4;
|
||||
ctxpc5.convert[5] = convert[2] & 0xF;
|
||||
|
||||
pc5decrypt(&ctxpc5);
|
||||
|
||||
// Store decrypted nibbles back in convert
|
||||
for (int i = 0; i < 6; i++) convert[i] = ctxpc5.convert[i];
|
||||
|
||||
// Recombine nibbles into bytes
|
||||
ctxpc5.convert[0] = (convert[0] << 4) + convert[1];
|
||||
ctxpc5.convert[1] = (convert[2] << 4) + convert[3];
|
||||
ctxpc5.convert[2] = (convert[4] << 4) + convert[5];
|
||||
|
||||
// Convert back to bits for first 24 bits
|
||||
for (int q = 0; q < 3; q++) {
|
||||
uint8_t w = (uint8_t)(q * 8);
|
||||
hexbinpc5(&ctxpc5, frame_bits_in, w, ctxpc5.convert[q]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 49; i++) ctxpc5.bits[i] = frame_bits_in[i];
|
||||
}
|
||||
|
||||
/* Convert 64-bit integer to bytes (big-endian) */
|
||||
static void u64_to_bytes_be_pc5(uint64_t val, unsigned char *out) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out[i] = (unsigned char)((val >> (56 - 8 * i)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
43
include/rc2.h
Normal file
43
include/rc2.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef RETEVIS_AP
|
||||
#define RETEVIS_AP
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dsd.h"
|
||||
|
||||
#define n1 264
|
||||
|
||||
typedef struct {
|
||||
uint8_t array_rc4[256];
|
||||
int i_rc4, j_rc4;
|
||||
uint64_t x;
|
||||
uint8_t xyz, count;
|
||||
uint64_t bb;
|
||||
} RC4State;
|
||||
|
||||
typedef struct {
|
||||
int x1, x2;
|
||||
unsigned char h2[n1];
|
||||
unsigned char h1[n1 * 3];
|
||||
} MD2State;
|
||||
|
||||
typedef struct {
|
||||
uint16_t xkey[64];
|
||||
uint8_t plain[8];
|
||||
uint8_t cipher[8];
|
||||
} RC2State;
|
||||
|
||||
typedef struct {
|
||||
RC4State rc4;
|
||||
MD2State md2;
|
||||
RC2State rc2;
|
||||
uint64_t internal_state;
|
||||
uint64_t internal_zero;
|
||||
uint8_t keys[16];
|
||||
} CryptoContext;
|
||||
|
||||
/* Public API */
|
||||
void create_keys_rc2(CryptoContext* ctx, unsigned char key1[], size_t size1);
|
||||
void encryption_rc2(CryptoContext* ctx, uint8_t s1[49]);
|
||||
void decrypt_rc2(CryptoContext* ctx, uint8_t bits[49]);
|
||||
|
||||
#endif
|
||||
417
src/crypt-kir.c
Normal file
417
src/crypt-kir.c
Normal file
@@ -0,0 +1,417 @@
|
||||
#include "dsd.h"
|
||||
#include "pc4.h"
|
||||
|
||||
/* === Global MD2II buffers === */
|
||||
int x1, x2, i, n1global;
|
||||
unsigned char h2[n1];
|
||||
unsigned char h1[n1*3];
|
||||
|
||||
/* === MD2II functions === */
|
||||
void MD2II_init()
|
||||
{
|
||||
x1 = 0;
|
||||
x2 = 0;
|
||||
for (i = 0; i < n1global; i++)
|
||||
h2[i] = 0;
|
||||
for (i = 0; i < n1global; i++)
|
||||
h1[i] = 0;
|
||||
}
|
||||
|
||||
void MD2II_hashing(unsigned char t1[], size_t b6)
|
||||
{
|
||||
static unsigned char s4[256] =
|
||||
{13,199,11,67,237,193,164,77,115,184,141,222,73,
|
||||
38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||
119,22,207,35,198,37,171,167,80,30,219,28,213,
|
||||
121,86,29,214,242,6,4,89,162,110,175,19,157,
|
||||
3,88,234,94,144,118,159,239,100,17,182,173,238,
|
||||
68,16,79,132,54,163,52,9,58,57,55,229,192,
|
||||
170,226,56,231,187,158,70,224,233,245,26,47,32,
|
||||
44,247,8,251,20,197,185,109,153,204,218,93,178,
|
||||
212,137,84,174,24,120,130,149,72,180,181,208,255,
|
||||
189,152,18,143,176,60,249,27,227,128,139,243,253,
|
||||
59,123,172,108,211,96,138,10,215,42,225,40,81,
|
||||
65,90,25,98,126,154,64,124,116,122,5,1,168,
|
||||
83,190,131,191,244,240,235,177,155,228,125,66,43,
|
||||
201,248,220,129,188,230,62,75,71,78,34,31,216,
|
||||
254,136,91,114,106,46,217,196,92,151,209,133,51,
|
||||
236,33,252,127,179,69,7,183,105,146,97,39,15,
|
||||
205,112,200,166,223,45,48,246,186,41,148,140,107,
|
||||
76,85,95,194,142,50,49,134,23,135,169,221,210,
|
||||
203,63,165,82,161,202,53,14,206,232,103,102,195,
|
||||
117,250,99,0,74,160,241,2,113};
|
||||
|
||||
int b1, b2, b3, b4 = 0, b5;
|
||||
|
||||
while (b6) {
|
||||
for (; b6 && x2 < n1global; b6--, x2++) {
|
||||
b5 = t1[b4++];
|
||||
h1[x2 + n1global] = b5;
|
||||
h1[x2 + (n1global*2)] = b5 ^ h1[x2];
|
||||
x1 = h2[x2] ^= s4[b5 ^ x1];
|
||||
}
|
||||
|
||||
if (x2 == n1global) {
|
||||
b2 = 0;
|
||||
x2 = 0;
|
||||
for (b3 = 0; b3 < (n1global+2); b3++) {
|
||||
for (b1 = 0; b1 < (n1global*3); b1++)
|
||||
b2 = h1[b1] ^= s4[b2];
|
||||
b2 = (b2 + b3) % 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MD2II_end(unsigned char h4[n1])
|
||||
{
|
||||
unsigned char h3[n1];
|
||||
int i, n4;
|
||||
n4 = n1global - x2;
|
||||
for (i = 0; i < n4; i++) h3[i] = n4;
|
||||
MD2II_hashing(h3, n4);
|
||||
MD2II_hashing(h2, n1global);
|
||||
for (i = 0; i < n1global; i++) h4[i] = h1[i];
|
||||
}
|
||||
|
||||
void print_hex(const unsigned char *buf, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
printf("%02X ", buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static inline uint64_t rol48(uint64_t x, int n)
|
||||
{
|
||||
return ((x << n) | (x >> 47)) & 0xffffffffffff;
|
||||
}
|
||||
|
||||
/* === Keystream (A5-like) === */
|
||||
static int threshold(uint64_t r1, uint64_t r2, uint64_t r3)
|
||||
{
|
||||
int total = (((r1 >> 31) & 1) == 1) +
|
||||
(((r2 >> 31) & 1) == 1) +
|
||||
(((r3 >> 31) & 1) == 1);
|
||||
return (total > 1) ? 0 : 1;
|
||||
}
|
||||
|
||||
static uint64_t clock_r1(int ctl, uint64_t r1)
|
||||
{
|
||||
ctl ^= ((r1 >> 31) & 1);
|
||||
if (ctl) {
|
||||
int taps[] = {0,3,5,9,10,11,12,17,18,28,33,34,35,36,37,39,42,43,44,46,47,49,50,57,60,61,62,63};
|
||||
uint64_t fb = 0;
|
||||
for(int i=0;i<sizeof(taps)/sizeof(int);i++) fb ^= (r1>>taps[i])&1ULL;
|
||||
r1 = (r1<<1)&0xFFFFFFFFFFFFFFFFULL;
|
||||
if(fb&1ULL) r1 ^= 1ULL;
|
||||
}
|
||||
return r1;
|
||||
}
|
||||
|
||||
static uint64_t clock_r2(int ctl, uint64_t r2)
|
||||
{
|
||||
ctl ^= ((r2 >> 31) & 1);
|
||||
if (ctl) {
|
||||
int taps[] = {0,3,5,8,9,10,12,13,15,17,19,20,21,22,24,27,30,31,33,34,35,36,37,40,41,42,51,52,55,56,59,60,62,63};
|
||||
uint64_t fb = 0;
|
||||
for(int i=0;i<sizeof(taps)/sizeof(int);i++) fb ^= (r2>>taps[i])&1ULL;
|
||||
r2 = (r2<<1)&0xFFFFFFFFFFFFFFFFULL;
|
||||
if(fb&1ULL) r2 ^= 1ULL;
|
||||
}
|
||||
return r2;
|
||||
}
|
||||
|
||||
static uint64_t clock_r3(int ctl, uint64_t r3)
|
||||
{
|
||||
ctl ^= ((r3 >> 31) & 1);
|
||||
if (ctl) {
|
||||
int taps[] = {1,2,4,5,6,7,8,9,10,14,15,16,17,18,22,23,25,26,27,28,29,31,32,34,35,36,38,41,42,43,44,45,47,48,49,50,51,54,55,59,61,63};
|
||||
uint64_t fb = 0;
|
||||
for(int i=0;i<sizeof(taps)/sizeof(int);i++) fb ^= (r3>>taps[i])&1ULL;
|
||||
r3 = (r3<<1)&0xFFFFFFFFFFFFFFFFULL;
|
||||
if(fb&1ULL) r3 ^= 1ULL;
|
||||
}
|
||||
return r3;
|
||||
}
|
||||
|
||||
void keystream37(unsigned char *key, uint64_t frame, unsigned char *output)
|
||||
{
|
||||
uint64_t r1=0,r2=0,r3=0;
|
||||
for(int i=0;i<8;i++) r1=(r1<<8)|key[i];
|
||||
for(int i=0;i<8;i++) r2=(r2<<8)|key[i+8];
|
||||
for(int i=0;i<8;i++) r3=(r3<<8)|key[i+16];
|
||||
|
||||
for(int i=0;i<64;i++){
|
||||
int ctl=threshold(r1,r2,r3);
|
||||
r1=clock_r1(ctl,r1);
|
||||
r2=clock_r2(ctl,r2);
|
||||
r3=clock_r3(ctl,r3);
|
||||
if(frame&1ULL){ r1^=1ULL; r2^=1ULL; r3^=1ULL;}
|
||||
frame>>=1;
|
||||
}
|
||||
|
||||
for(int i=0;i<384;i++){
|
||||
int ctl=threshold(r1,r2,r3);
|
||||
r1=clock_r1(ctl,r1);
|
||||
r2=clock_r2(ctl,r2);
|
||||
r3=clock_r3(ctl,r3);
|
||||
}
|
||||
|
||||
unsigned char *ptr=output;
|
||||
unsigned char byte=0;
|
||||
int bits=0;
|
||||
for(int i=0;i<1008;i++){
|
||||
int ctl=threshold(r1,r2,r3);
|
||||
r1=clock_r1(ctl,r1);
|
||||
r2=clock_r2(ctl,r2);
|
||||
r3=clock_r3(ctl,r3);
|
||||
int bit=((r1>>63)^(r2>>63)^(r3>>63))&1U;
|
||||
byte=(byte<<1)|bit;
|
||||
bits++;
|
||||
if(bits==8){*ptr++=byte; bits=0; byte=0;}
|
||||
}
|
||||
if(bits) *ptr=byte;
|
||||
|
||||
}
|
||||
|
||||
//dsd-fme -fs -Z -i '/SSD_STORAGE/2025_DEV/Tytera BP EP AP Master Folder/kirisun/cap-clear.wav/cap-33.wav' -H '3333333333333333 3333333333333333 3333333333333333 3333333333333333'
|
||||
void kirisun_uni_keystream_creation(dsd_state *state)
|
||||
{
|
||||
uint8_t slot = 0;
|
||||
if (state->currentslot == 0)
|
||||
slot = 0;
|
||||
else slot = 1;
|
||||
|
||||
uint32_t lfsr = 0;
|
||||
if (state->currentslot == 0)
|
||||
lfsr = (uint32_t)state->payload_mi;
|
||||
else lfsr = (uint32_t)state->payload_miR;
|
||||
|
||||
unsigned char userkeyhexa[32]; memset(userkeyhexa, 0, sizeof(userkeyhexa));
|
||||
unsigned char realkey[32]; memset(realkey, 0, sizeof(realkey));
|
||||
unsigned char lfsrhexa[4]; memset(lfsrhexa, 0, sizeof(lfsrhexa));
|
||||
uint8_t ks_bytes[126]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
|
||||
lfsrhexa[0] = (lfsr >> 24) & 0xFF;
|
||||
lfsrhexa[1] = (lfsr >> 16) & 0xFF;
|
||||
lfsrhexa[2] = (lfsr >> 8) & 0xFF;
|
||||
lfsrhexa[3] = (lfsr >> 0) & 0xFF;
|
||||
|
||||
uint64_t K1 = state->A1[slot];
|
||||
uint64_t K2 = state->A2[slot];
|
||||
uint64_t K3 = state->A3[slot];
|
||||
uint64_t K4 = state->A4[slot];
|
||||
|
||||
if (K1 != 0 && K2 != 0 && K3 != 0 && K4 != 0)
|
||||
state->aes_key_loaded[slot] = 1;
|
||||
else state->aes_key_loaded[slot] = 0;
|
||||
|
||||
if (state->aes_key_loaded[slot] == 1)
|
||||
{
|
||||
|
||||
u64_to_bytes_be(K1, &userkeyhexa[0]);
|
||||
u64_to_bytes_be(K2, &userkeyhexa[8]);
|
||||
u64_to_bytes_be(K3, &userkeyhexa[16]);
|
||||
u64_to_bytes_be(K4, &userkeyhexa[24]);
|
||||
|
||||
for(int i=0;i<32;i++) realkey[i]=userkeyhexa[i];
|
||||
|
||||
/* --- MD2II first pass --- */
|
||||
n1global=32;
|
||||
unsigned char h4[n1]; memset(h4, 0, sizeof(h4));
|
||||
MD2II_init();
|
||||
MD2II_hashing(realkey,32);
|
||||
MD2II_end(h4);
|
||||
for(int i=0;i<32;i++) realkey[i]=h4[i];
|
||||
|
||||
// printf("=== realkey final (32 bytes) ===\n");
|
||||
// print_hex(realkey,32);
|
||||
|
||||
/* --- MD2II with n1global=8, hash lfsr byte by byte --- */
|
||||
unsigned char hashtag[1];
|
||||
|
||||
n1global=8;
|
||||
MD2II_init();
|
||||
for(int i=0;i<4;i++)
|
||||
{
|
||||
hashtag[0] = (lfsr >> (24-8*i)) & 0xFF;
|
||||
MD2II_hashing(hashtag,1);
|
||||
}
|
||||
MD2II_hashing(realkey,32);
|
||||
MD2II_end(h4);
|
||||
|
||||
// printf("h4[0..7]: ");
|
||||
// print_hex(h4,8);
|
||||
|
||||
uint64_t internal_state=0;
|
||||
for(int i=0;i<8;i++)
|
||||
internal_state=(internal_state<<8)+(h4[i]);
|
||||
|
||||
// printf("internal_state=%016llX\n",(unsigned long long)internal_state);
|
||||
|
||||
/* --- MD2II with n1global=24 --- */
|
||||
n1global=24;
|
||||
MD2II_init();
|
||||
for(int i=0;i<4;i++)
|
||||
{
|
||||
hashtag[0] = (lfsr >> (24-8*i)) & 0xFF;
|
||||
MD2II_hashing(hashtag,1);
|
||||
}
|
||||
MD2II_hashing(realkey,32);
|
||||
MD2II_end(h4);
|
||||
|
||||
// printf("realkey (24 bytes):\n");
|
||||
// print_hex(h4,24);
|
||||
|
||||
/* --- keystream output --- */
|
||||
unsigned char output[126]; memset(output, 0, sizeof(output));
|
||||
keystream37(h4, internal_state, output);
|
||||
|
||||
// printf("keystream output (126 bytes):\n");
|
||||
// print_hex(output,126);
|
||||
|
||||
//store ks_bytes to storage
|
||||
for (int i = 0; i < 126; i++)
|
||||
ks_bytes[i] = (uint8_t)output[i];
|
||||
|
||||
if (slot == 0)
|
||||
memcpy(state->ks_octetL, ks_bytes, sizeof(ks_bytes));
|
||||
else memcpy(state->ks_octetR, ks_bytes, sizeof(ks_bytes));
|
||||
|
||||
//debug ks_bytes
|
||||
// fprintf (stderr, "KS: ");
|
||||
// for (int i = 0; i < 126; i++)
|
||||
// {
|
||||
// if ((i != 0) && ((i%16)==0))
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, "%02X ", ks_bytes[i]);
|
||||
// }
|
||||
// fprintf (stderr, "\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//dsd-fme -fs -Z -i '/SSD_STORAGE/2025_DEV/Tytera BP EP AP Master Folder/kirisun/better_samples_tg1/kirisun_advanced_tg1.wav' -H 'DC1A7E9F9BF312DB F45010CEC5F7A53A C407D0BFA803617B E426A7254DA9390D'
|
||||
void kirisun_adv_keystream_creation(dsd_state *state)
|
||||
{
|
||||
|
||||
uint8_t slot = 0;
|
||||
if (state->currentslot == 0)
|
||||
slot = 0;
|
||||
else slot = 1;
|
||||
|
||||
uint32_t lfsr = 0;
|
||||
if (state->currentslot == 0)
|
||||
lfsr = (uint32_t)state->payload_mi;
|
||||
else lfsr = (uint32_t)state->payload_miR;
|
||||
|
||||
unsigned char userkeyhexa[32]; memset(userkeyhexa, 0, sizeof(userkeyhexa));
|
||||
unsigned char realkey[32]; memset(realkey, 0, sizeof(realkey));
|
||||
unsigned char lfsrhexa[4]; memset(lfsrhexa, 0, sizeof(lfsrhexa));
|
||||
uint8_t ks_bytes[126]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
|
||||
lfsrhexa[0] = (lfsr >> 24) & 0xFF;
|
||||
lfsrhexa[1] = (lfsr >> 16) & 0xFF;
|
||||
lfsrhexa[2] = (lfsr >> 8) & 0xFF;
|
||||
lfsrhexa[3] = (lfsr >> 0) & 0xFF;
|
||||
|
||||
uint64_t K1 = state->A1[slot];
|
||||
uint64_t K2 = state->A2[slot];
|
||||
uint64_t K3 = state->A3[slot];
|
||||
uint64_t K4 = state->A4[slot];
|
||||
|
||||
if (K1 != 0 && K2 != 0 && K3 != 0 && K4 != 0)
|
||||
state->aes_key_loaded[slot] = 1;
|
||||
else state->aes_key_loaded[slot] = 0;
|
||||
|
||||
if (state->aes_key_loaded[slot] == 1)
|
||||
{
|
||||
|
||||
u64_to_bytes_be(K1, &userkeyhexa[0]);
|
||||
u64_to_bytes_be(K2, &userkeyhexa[8]);
|
||||
u64_to_bytes_be(K3, &userkeyhexa[16]);
|
||||
u64_to_bytes_be(K4, &userkeyhexa[24]);
|
||||
|
||||
//init vital portions of PC4Context
|
||||
ctx.x1 = 0;
|
||||
ctx.x2 = 0;
|
||||
for (ctx.i = 0; ctx.i < n1; ctx.i++) ctx.h2[ctx.i] = 0;
|
||||
for (ctx.i = 0; ctx.i < n1; ctx.i++) ctx.h1[ctx.i] = 0;
|
||||
ctx.rounds = nbround;
|
||||
|
||||
//create keys
|
||||
create_keys(&ctx, userkeyhexa, 32);
|
||||
|
||||
/* --- MD2II first pass --- */
|
||||
n1global=32;
|
||||
unsigned char h4[n1]; memset(h4, 0, sizeof(h4));
|
||||
MD2II_init();
|
||||
MD2II_hashing(userkeyhexa,32);
|
||||
MD2II_end(h4);
|
||||
for(int i=0;i<32;i++) realkey[i]=h4[i];
|
||||
|
||||
// printf("=== realkey final (32 bytes) ===\n");
|
||||
// print_hex(realkey,32);
|
||||
|
||||
n1global=32;
|
||||
memset(h4, 0, sizeof(h4));
|
||||
MD2II_init();
|
||||
MD2II_hashing(lfsrhexa,4);
|
||||
MD2II_hashing(realkey,32);
|
||||
MD2II_end(h4);
|
||||
|
||||
// printf("h4[0..7]: ");
|
||||
// print_hex(h4,8);
|
||||
|
||||
uint64_t internal_state=0;
|
||||
for(int i=0;i<6;i++)
|
||||
internal_state=(internal_state<<8)+(h4[i]);
|
||||
|
||||
int k = 0;
|
||||
for (int i = 0; i < 18; i++)
|
||||
{
|
||||
|
||||
//debug internal_state
|
||||
// fprintf (stderr, "ST: %012lX; \n", internal_state);
|
||||
|
||||
ctx.convert[0]=(internal_state>>40)&0xff;
|
||||
ctx.convert[1]=(internal_state>>32)&0xff;
|
||||
ctx.convert[2]=(internal_state>>24)&0xff;
|
||||
ctx.convert[3]=(internal_state>>16)&0xff;
|
||||
ctx.convert[4]=(internal_state>>8)&0xff;
|
||||
ctx.convert[5]=internal_state&0xff;
|
||||
|
||||
pc4encrypt(&ctx);
|
||||
|
||||
internal_state=0;
|
||||
for (int i=0;i<6;i++)
|
||||
internal_state=(internal_state<<8)+(ctx.convert[i]&0xff);
|
||||
|
||||
internal_state=rol48(internal_state,1);
|
||||
|
||||
//keystream
|
||||
for (int i=0;i<6;i++)
|
||||
ks_bytes[k++] = ctx.convert[i];
|
||||
k++; //skip 7th octet
|
||||
|
||||
}
|
||||
|
||||
//store ks_bytes to storage
|
||||
if (slot == 0)
|
||||
memcpy(state->ks_octetL, ks_bytes, sizeof(ks_bytes));
|
||||
else memcpy(state->ks_octetR, ks_bytes, sizeof(ks_bytes));
|
||||
|
||||
//debug ks_bytes
|
||||
// fprintf (stderr, "KS: ");
|
||||
// for (int i = 0; i < 126; i++)
|
||||
// {
|
||||
// if ((i != 0) && ((i%16)==0))
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, "%02X ", ks_bytes[i]);
|
||||
// }
|
||||
// fprintf (stderr, "\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
468
src/crypt-pc5.c
Normal file
468
src/crypt-pc5.c
Normal file
@@ -0,0 +1,468 @@
|
||||
#include "pc5.h"
|
||||
#include "dsd.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* Global PC5 context instance */
|
||||
PC5Context ctxpc5;
|
||||
|
||||
/* ---------------------------------
|
||||
Internal utility functions
|
||||
----------------------------------- */
|
||||
|
||||
/* Rotate right */
|
||||
static uint32_t ror(uint32_t x, int shift, int bits) {
|
||||
uint32_t m0 = (1u << (bits - shift)) - 1u;
|
||||
uint32_t m1 = (1u << shift) - 1u;
|
||||
return ((x >> shift) & m0) | ((x & m1) << (bits - shift));
|
||||
}
|
||||
|
||||
/* Rotate left */
|
||||
static uint32_t rol(uint32_t x, int shift, int bits) {
|
||||
uint32_t m0 = (1u << (bits - shift)) - 1u;
|
||||
uint32_t m1 = (1u << shift) - 1u;
|
||||
return ((x & m0) << shift) | ((x >> (bits - shift)) & m1);
|
||||
}
|
||||
|
||||
/* SplitMix64 random number generator */
|
||||
static uint64_t next_rng(PC5Context *ctxpc5) {
|
||||
uint64_t z = (ctxpc5->x += 0x9e3779b97f4a7c15ULL);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
/* ARC4 initialization */
|
||||
static void arc4_init(PC5Context *ctxpc5, unsigned char key[]) {
|
||||
int tmp;
|
||||
for (ctxpc5->i_arc4 = 0; ctxpc5->i_arc4 < 256; ctxpc5->i_arc4++)
|
||||
ctxpc5->array_arc4[ctxpc5->i_arc4] = (unsigned char)ctxpc5->i_arc4;
|
||||
|
||||
ctxpc5->j_arc4 = 0;
|
||||
for (ctxpc5->i_arc4 = 0; ctxpc5->i_arc4 < 256; ctxpc5->i_arc4++) {
|
||||
ctxpc5->j_arc4 = (ctxpc5->j_arc4 + ctxpc5->array_arc4[ctxpc5->i_arc4] + key[ctxpc5->i_arc4 % 256]) % 256;
|
||||
tmp = ctxpc5->array_arc4[ctxpc5->i_arc4];
|
||||
ctxpc5->array_arc4[ctxpc5->i_arc4] = ctxpc5->array_arc4[ctxpc5->j_arc4];
|
||||
ctxpc5->array_arc4[ctxpc5->j_arc4] = tmp;
|
||||
}
|
||||
ctxpc5->i_arc4 = 0;
|
||||
ctxpc5->j_arc4 = 0;
|
||||
}
|
||||
|
||||
/* ARC4 output combined with SplitMix64 stream */
|
||||
static unsigned char arc4_output(PC5Context *ctxpc5) {
|
||||
uint8_t rndbyte, decal;
|
||||
int tmp, t;
|
||||
|
||||
ctxpc5->i_arc4 = (ctxpc5->i_arc4 + 1) % 256;
|
||||
ctxpc5->j_arc4 = (ctxpc5->j_arc4 + ctxpc5->array_arc4[ctxpc5->i_arc4]) % 256;
|
||||
tmp = ctxpc5->array_arc4[ctxpc5->i_arc4];
|
||||
ctxpc5->array_arc4[ctxpc5->i_arc4] = ctxpc5->array_arc4[ctxpc5->j_arc4];
|
||||
ctxpc5->array_arc4[ctxpc5->j_arc4] = tmp;
|
||||
t = (ctxpc5->array_arc4[ctxpc5->i_arc4] + ctxpc5->array_arc4[ctxpc5->j_arc4]) % 256;
|
||||
|
||||
if (ctxpc5->xyz == 0) ctxpc5->bb = next_rng(ctxpc5);
|
||||
decal = (uint8_t)(56 - (8 * ctxpc5->xyz));
|
||||
rndbyte = (uint8_t)((ctxpc5->bb >> decal) & 0xffu);
|
||||
ctxpc5->xyz++;
|
||||
if (ctxpc5->xyz == 8) ctxpc5->xyz = 0;
|
||||
|
||||
if (ctxpc5->count == 0) {
|
||||
rndbyte = (uint8_t)(rndbyte ^ ctxpc5->array_arc4[t]);
|
||||
ctxpc5->count = 1;
|
||||
} else {
|
||||
rndbyte = (uint8_t)(rndbyte + ctxpc5->array_arc4[t]);
|
||||
ctxpc5->count = 0;
|
||||
}
|
||||
return rndbyte;
|
||||
}
|
||||
|
||||
/* Initialize MD2-II state */
|
||||
static void md2_init(PC5Context *ctxpc5) {
|
||||
ctxpc5->x1 = 0;
|
||||
ctxpc5->x2 = 0;
|
||||
for (ctxpc5->i = 0; ctxpc5->i < n1; ctxpc5->i++) ctxpc5->h2[ctxpc5->i] = 0;
|
||||
for (ctxpc5->i = 0; ctxpc5->i < n1; ctxpc5->i++) ctxpc5->h1[ctxpc5->i] = 0;
|
||||
}
|
||||
|
||||
/* MD2-II hashing */
|
||||
static void md2_hashing(PC5Context *ctxpc5, unsigned char t1[], size_t b6) {
|
||||
static const unsigned char s4[256] = {
|
||||
13,199,11,67,237,193,164,77,115,184,141,222,73,38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||
119,22,207,35,198,37,171,167,80,30,219,28,213,121,86,29,214,242,6,4,89,162,110,175,19,157,3,
|
||||
88,234,94,144,118,159,239,100,17,182,173,238,68,16,79,132,54,163,52,9,58,57,55,229,192,170,226,
|
||||
56,231,187,158,70,224,233,245,26,47,32,44,247,8,251,20,197,185,109,153,204,218,93,178,212,137,84,
|
||||
174,24,120,130,149,72,180,181,208,255,189,152,18,143,176,60,249,27,227,128,139,243,253,59,123,172,
|
||||
108,211,96,138,10,215,42,225,40,81,65,90,25,98,126,154,64,124,116,122,5,1,168,83,190,131,191,244,
|
||||
240,235,177,155,228,125,66,43,201,248,220,129,188,230,62,75,71,78,34,31,216,254,136,91,114,106,46,
|
||||
217,196,92,151,209,133,51,236,33,252,127,179,69,7,183,105,146,97,39,15,205,112,200,166,223,45,48,
|
||||
246,186,41,148,140,107,76,85,95,194,142,50,49,134,23,135,169,221,210,203,63,165,82,161,202,53,14,
|
||||
206,232,103,102,195,117,250,99,0,74,160,241,2,113};
|
||||
|
||||
int b1, b2, b3, b4, b5;
|
||||
b4 = 0;
|
||||
while (b6) {
|
||||
for (; b6 && ctxpc5->x2 < n1; b6--, ctxpc5->x2++) {
|
||||
b5 = t1[b4++];
|
||||
ctxpc5->h1[ctxpc5->x2 + n1] = (unsigned char)b5;
|
||||
ctxpc5->h1[ctxpc5->x2 + (n1 * 2)] = (unsigned char)(b5 ^ ctxpc5->h1[ctxpc5->x2]);
|
||||
ctxpc5->x1 = ctxpc5->h2[ctxpc5->x2] ^= s4[b5 ^ ctxpc5->x1];
|
||||
}
|
||||
if (ctxpc5->x2 == n1) {
|
||||
b2 = 0;
|
||||
ctxpc5->x2 = 0;
|
||||
for (b3 = 0; b3 < (n1 + 2); b3++) {
|
||||
for (b1 = 0; b1 < (n1 * 3); b1++)
|
||||
b2 = ctxpc5->h1[b1] ^= s4[b2];
|
||||
b2 = (b2 + b3) % 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finalize MD2-II */
|
||||
static void md2_end(PC5Context *ctxpc5, unsigned char h4[n1]) {
|
||||
unsigned char h3[n1];
|
||||
int i, n4 = n1 - ctxpc5->x2;
|
||||
for (i = 0; i < n4; i++) h3[i] = (unsigned char)n4;
|
||||
md2_hashing(ctxpc5, h3, (size_t)n4);
|
||||
md2_hashing(ctxpc5, ctxpc5->h2, sizeof(ctxpc5->h2));
|
||||
for (i = 0; i < n1; i++) h4[i] = ctxpc5->h1[i];
|
||||
}
|
||||
|
||||
/* Generate a random index */
|
||||
static int mixy(PC5Context *ctxpc5, int nn2) {
|
||||
return arc4_output(ctxpc5) % nn2;
|
||||
}
|
||||
|
||||
/* Fisher-Yates shuffle */
|
||||
static void mixer(PC5Context *ctxpc5, uint8_t *mixu, int nn) {
|
||||
int ii, jj, tmmp;
|
||||
for (ii = nn - 1; ii > 0; ii--) {
|
||||
jj = mixy(ctxpc5, ii + 1);
|
||||
tmmp = mixu[jj];
|
||||
mixu[jj] = mixu[ii];
|
||||
mixu[ii] = (uint8_t)tmmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Key schedule and S-box generation */
|
||||
void create_keys_pc5(PC5Context *ctxpc5, unsigned char key1[], size_t size1) {
|
||||
int i, w, k;
|
||||
unsigned char h4[n1];
|
||||
|
||||
md2_init(ctxpc5);
|
||||
md2_hashing(ctxpc5, key1, size1);
|
||||
md2_end(ctxpc5, h4);
|
||||
|
||||
for (i = 0; i < 16; i++) ctxpc5->keys[i] = h4[i];
|
||||
arc4_init(ctxpc5, h4);
|
||||
|
||||
ctxpc5->x = 0;
|
||||
for (i = 0; i < 8; i++) ctxpc5->x = (ctxpc5->x << 8) + (uint64_t)(h4[256 + i] & 0xffu);
|
||||
|
||||
ctxpc5->xyz = 0;
|
||||
ctxpc5->count = 0;
|
||||
|
||||
for (i = 0; i < 23000; i++) (void)arc4_output(ctxpc5);
|
||||
|
||||
uint8_t numbers[256];
|
||||
|
||||
for (w = 0; w < 253; w++) {
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (i = 0; i < 16; i++) numbers[i] = (uint8_t)i;
|
||||
mixer(ctxpc5, numbers, 16);
|
||||
for (i = 0; i < 16; i++) ctxpc5->perm[i][w] = numbers[i];
|
||||
}
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (i = 0; i < 16; i++) numbers[i] = (uint8_t)i;
|
||||
mixer(ctxpc5, numbers, 16);
|
||||
for (i = 0; i < 16; i++) ctxpc5->new1[i] = numbers[i];
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (i = 0; i < nbround; i++) ctxpc5->decal[i] = (uint8_t)((arc4_output(ctxpc5) % 11) + 1);
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (w = 0; w < 3; w++)
|
||||
for (i = 0; i < nbround; i++)
|
||||
ctxpc5->rngxor[i][w] = arc4_output(ctxpc5) % 16;
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (i = 0; i < 16; i++) numbers[i] = (uint8_t)i;
|
||||
mixer(ctxpc5, numbers, 16);
|
||||
for (i = 0; i < 16; i++) {
|
||||
ctxpc5->tab[i] = numbers[i];
|
||||
ctxpc5->inv[ctxpc5->tab[i]] = (unsigned char)i;
|
||||
}
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (w = 0; w < 3; w++) {
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (i = 0; i < 3; i++) numbers[i] = (uint8_t)i;
|
||||
mixer(ctxpc5, numbers, 3);
|
||||
for (i = 0; i < 3; i++) ctxpc5->permut[w][i] = numbers[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||
for (w = 0; w < 3; w++)
|
||||
for (i = 0; i < nbround; i++)
|
||||
ctxpc5->rngxor2[i][w] = arc4_output(ctxpc5) % 16;
|
||||
|
||||
k = arc4_output(ctxpc5) + 256;
|
||||
|
||||
for (w = 0; w < 25; w++) ctxpc5->numbers[w]=arc4_output(ctxpc5) % 2;
|
||||
|
||||
}
|
||||
|
||||
static void compute_pc5(PC5Context *ctxpc5, uint8_t *tab1, uint8_t round) {
|
||||
ctxpc5->tot[0] = (uint8_t)((ctxpc5->perm[tab1[ctxpc5->permut[0][0]]][round] +
|
||||
ctxpc5->perm[tab1[ctxpc5->permut[0][1]]][round]) ^
|
||||
ctxpc5->perm[tab1[ctxpc5->permut[0][2]]][round]);
|
||||
ctxpc5->tot[0] = (uint8_t)((ctxpc5->tot[0] + ctxpc5->new1[ctxpc5->tot[0]]) % 16);
|
||||
ctxpc5->tot[1] = (uint8_t)((ctxpc5->perm[tab1[ctxpc5->permut[1][0]]][round] +
|
||||
ctxpc5->perm[tab1[ctxpc5->permut[1][1]]][round]) ^
|
||||
ctxpc5->perm[tab1[ctxpc5->permut[1][2]]][round]);
|
||||
ctxpc5->tot[1] = (uint8_t)((ctxpc5->tot[1] + ctxpc5->new1[ctxpc5->tot[1]]) % 16);
|
||||
ctxpc5->tot[2] = (uint8_t)((ctxpc5->perm[tab1[ctxpc5->permut[2][0]]][round] +
|
||||
ctxpc5->perm[tab1[ctxpc5->permut[2][1]]][round]) ^
|
||||
ctxpc5->perm[tab1[ctxpc5->permut[2][2]]][round]);
|
||||
ctxpc5->tot[2] = (uint8_t)((ctxpc5->tot[2] + ctxpc5->new1[ctxpc5->tot[2]]) % 16);
|
||||
}
|
||||
|
||||
/* Convert bits to bytes */
|
||||
void binhexpc5(PC5Context *ctxpc5, short *z, int length) {
|
||||
short *b = (short *)z;
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < length; i = j) {
|
||||
uint8_t a = 0;
|
||||
for (j = i; j < i + 8; ++j) {
|
||||
a |= (uint8_t)(b[((short)(7 - (j % 8)) + j) - (j % 8)] << (j - i));
|
||||
}
|
||||
ctxpc5->convert[ctxpc5->ptconvert] = a;
|
||||
ctxpc5->ptconvert++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert byte to bits */
|
||||
void hexbinpc5(PC5Context *ctxpc5, short *q, uint8_t w, uint8_t hex) { // warning: unused parameter ‘ctxpc5’ [-Wunused-parameter]
|
||||
UNUSED(ctxpc5);
|
||||
short *bits = (short *)q;
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
bits[(short)(7 + w) - i] = (short)((hex >> i) & 1u);
|
||||
}
|
||||
|
||||
// UNUSEDPC4(ctxpc5); //fix above warning
|
||||
}
|
||||
|
||||
/* Encrypt one block */
|
||||
void pc5encrypt(PC5Context *ctxpc5) {
|
||||
int i;
|
||||
int g;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ctxpc5->l[0][i] = ctxpc5->convert[i];
|
||||
ctxpc5->r[0][i] = ctxpc5->convert[i + 3];
|
||||
}
|
||||
|
||||
for (i = 1; i <= ctxpc5->rounds; i++) {
|
||||
ctxpc5->r[(i - 1) % 2][0] = (ctxpc5->r[(i - 1) % 2][0] + ((uint8_t)~ctxpc5->rngxor2[ctxpc5->rounds - i][0])) % 16;
|
||||
ctxpc5->r[(i - 1) % 2][1] = (ctxpc5->r[(i - 1) % 2][1] ^ ((uint8_t)~ctxpc5->rngxor2[ctxpc5->rounds - i][1])) % 16;
|
||||
ctxpc5->r[(i - 1) % 2][2] = (ctxpc5->r[(i - 1) % 2][2] + ((uint8_t)~ctxpc5->rngxor2[ctxpc5->rounds - i][2])) % 16;
|
||||
|
||||
ctxpc5->result = 0;
|
||||
ctxpc5->result += ((uint32_t)ctxpc5->r[(i - 1) % 2][0] << 8);
|
||||
ctxpc5->result += ((uint32_t)ctxpc5->r[(i - 1) % 2][1] << 4);
|
||||
ctxpc5->result += ctxpc5->r[(i - 1) % 2][2];
|
||||
|
||||
ctxpc5->result = rol(ctxpc5->result, ctxpc5->decal[i - 1], 12);
|
||||
|
||||
ctxpc5->r[(i - 1) % 2][0] = (uint8_t)(ctxpc5->result >> 8);
|
||||
ctxpc5->r[(i - 1) % 2][1] = (uint8_t)((ctxpc5->result >> 4) & 0xfu);
|
||||
ctxpc5->r[(i - 1) % 2][2] = (uint8_t)(ctxpc5->result & 0xfu);
|
||||
|
||||
ctxpc5->r[(i - 1) % 2][0] = ctxpc5->tab[ctxpc5->r[(i - 1) % 2][0]];
|
||||
ctxpc5->r[(i - 1) % 2][0] = (ctxpc5->r[(i - 1) % 2][0] ^ ctxpc5->rngxor[i - 1][0]) % 16;
|
||||
|
||||
ctxpc5->r[(i - 1) % 2][1] = ctxpc5->inv[ctxpc5->r[(i - 1) % 2][1]];
|
||||
|
||||
if ((ctxpc5->r[(i - 1) % 2][1] - ctxpc5->rngxor[i - 1][1]) < 0) {
|
||||
g = (ctxpc5->r[(i - 1) % 2][1] - ctxpc5->rngxor[i - 1][1]) + 16;
|
||||
} else {
|
||||
g = (ctxpc5->r[(i - 1) % 2][1] - ctxpc5->rngxor[i - 1][1]) % 16;
|
||||
}
|
||||
ctxpc5->r[(i - 1) % 2][1] = g;
|
||||
|
||||
ctxpc5->r[(i - 1) % 2][2] = ctxpc5->tab[ctxpc5->r[(i - 1) % 2][2]];
|
||||
ctxpc5->r[(i - 1) % 2][2] = (ctxpc5->r[(i - 1) % 2][2] ^ ctxpc5->rngxor[i - 1][2]) % 16;
|
||||
|
||||
compute_pc5(ctxpc5, ctxpc5->r[(i - 1) % 2], (uint8_t)((i - 1) % 253));
|
||||
|
||||
ctxpc5->l[i % 2][0] = ctxpc5->r[(i - 1) % 2][0];
|
||||
|
||||
if ((ctxpc5->l[(i - 1) % 2][0] - ctxpc5->tot[0]) < 0) {
|
||||
g = (ctxpc5->l[(i - 1) % 2][0] - ctxpc5->tot[0]) + 16;
|
||||
} else {
|
||||
g = ctxpc5->l[(i - 1) % 2][0] - ctxpc5->tot[0];
|
||||
}
|
||||
ctxpc5->r[i % 2][0] = g;
|
||||
|
||||
ctxpc5->l[i % 2][1] = ctxpc5->r[(i - 1) % 2][1];
|
||||
ctxpc5->r[i % 2][1] = (ctxpc5->l[(i - 1) % 2][1] ^ ctxpc5->tot[1]) % 16;
|
||||
|
||||
ctxpc5->l[i % 2][2] = ctxpc5->r[(i - 1) % 2][2];
|
||||
|
||||
if ((ctxpc5->l[(i - 1) % 2][2] - ctxpc5->tot[2]) < 0) {
|
||||
g = (ctxpc5->l[(i - 1) % 2][2] - ctxpc5->tot[2]) + 16;
|
||||
} else {
|
||||
g = ctxpc5->l[(i - 1) % 2][2] - ctxpc5->tot[2];
|
||||
}
|
||||
ctxpc5->r[i % 2][2] = g;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ctxpc5->convert[i + 3] = ctxpc5->l[(ctxpc5->rounds - 1) % 2][i];
|
||||
ctxpc5->convert[i] = ctxpc5->r[(ctxpc5->rounds - 1) % 2][i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrypt one block */
|
||||
void pc5decrypt(PC5Context *ctxpc5) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ctxpc5->l[0][i] = ctxpc5->convert[i];
|
||||
ctxpc5->r[0][i] = ctxpc5->convert[i + 3];
|
||||
}
|
||||
|
||||
ctxpc5->y = (uint8_t)((ctxpc5->rounds - 1) % 253);
|
||||
if (ctxpc5->y == 0) ctxpc5->y = 253;
|
||||
|
||||
for (i = 1; i <= ctxpc5->rounds; i++) {
|
||||
ctxpc5->y--;
|
||||
compute_pc5(ctxpc5, ctxpc5->r[(i - 1) % 2], ctxpc5->y);
|
||||
if (ctxpc5->y == 0) ctxpc5->y = 253;
|
||||
|
||||
ctxpc5->result = 0;
|
||||
|
||||
ctxpc5->l[(i - 1) % 2][0] ^= ctxpc5->rngxor[ctxpc5->rounds - i][0];
|
||||
ctxpc5->l[(i - 1) % 2][0] %= 16;
|
||||
ctxpc5->l[(i - 1) % 2][0] = ctxpc5->inv[ctxpc5->l[(i - 1) % 2][0]];
|
||||
|
||||
ctxpc5->l[(i - 1) % 2][1] += ctxpc5->rngxor[ctxpc5->rounds - i][1];
|
||||
ctxpc5->l[(i - 1) % 2][1] %= 16;
|
||||
ctxpc5->l[(i - 1) % 2][1] = ctxpc5->tab[ctxpc5->l[(i - 1) % 2][1]];
|
||||
|
||||
ctxpc5->l[(i - 1) % 2][2] ^= ctxpc5->rngxor[ctxpc5->rounds - i][2];
|
||||
ctxpc5->l[(i - 1) % 2][2] %= 16;
|
||||
ctxpc5->l[(i - 1) % 2][2] = ctxpc5->inv[ctxpc5->l[(i - 1) % 2][2]];
|
||||
|
||||
ctxpc5->result += ((uint32_t)ctxpc5->l[(i - 1) % 2][0] << 8);
|
||||
ctxpc5->result += ((uint32_t)ctxpc5->l[(i - 1) % 2][1] << 4);
|
||||
ctxpc5->result += ctxpc5->l[(i - 1) % 2][2];
|
||||
|
||||
ctxpc5->result = ror(ctxpc5->result, ctxpc5->decal[ctxpc5->rounds - i], 12);
|
||||
|
||||
ctxpc5->l[(i - 1) % 2][0] = (uint8_t)(ctxpc5->result >> 8);
|
||||
ctxpc5->l[(i - 1) % 2][1] = (uint8_t)((ctxpc5->result >> 4) & 0xfu);
|
||||
ctxpc5->l[(i - 1) % 2][2] = (uint8_t)(ctxpc5->result & 0xfu);
|
||||
|
||||
int temp;
|
||||
|
||||
temp = ctxpc5->l[(i - 1) % 2][0] - ((uint8_t)(~ctxpc5->rngxor2[i - 1][0]) % 16);
|
||||
if (temp < 0) temp += 16;
|
||||
ctxpc5->l[(i - 1) % 2][0] = temp % 16;
|
||||
|
||||
ctxpc5->l[(i - 1) % 2][1] ^= (uint8_t)(~ctxpc5->rngxor2[i - 1][1]) % 16;
|
||||
ctxpc5->l[(i - 1) % 2][1] %= 16;
|
||||
|
||||
temp = ctxpc5->l[(i - 1) % 2][2] - ((uint8_t)(~ctxpc5->rngxor2[i - 1][2]) % 16);
|
||||
if (temp < 0) temp += 16;
|
||||
ctxpc5->l[(i - 1) % 2][2] = temp % 16;
|
||||
|
||||
ctxpc5->l[i % 2][0] = ctxpc5->r[(i - 1) % 2][0];
|
||||
ctxpc5->r[i % 2][0] = (ctxpc5->l[(i - 1) % 2][0] + ctxpc5->tot[0]) % 16;
|
||||
|
||||
ctxpc5->l[i % 2][1] = ctxpc5->r[(i - 1) % 2][1];
|
||||
ctxpc5->r[i % 2][1] = (ctxpc5->l[(i - 1) % 2][1] ^ ctxpc5->tot[1]) % 16;
|
||||
|
||||
ctxpc5->l[i % 2][2] = ctxpc5->r[(i - 1) % 2][2];
|
||||
ctxpc5->r[i % 2][2] = (ctxpc5->l[(i - 1) % 2][2] + ctxpc5->tot[2]) % 16;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ctxpc5->convert[i + 3] = ctxpc5->l[(ctxpc5->rounds - 1) % 2][i];
|
||||
ctxpc5->convert[i] = ctxpc5->r[(ctxpc5->rounds - 1) % 2][i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Key creation for BAOFENG AP */
|
||||
void baofeng_ap_pc5_keystream_creation(dsd_state *state, char *input) {
|
||||
|
||||
char buf[1024];
|
||||
strncpy(buf, input, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
// Count hexadecimal characters (without spaces)
|
||||
int hex_char_count = 0;
|
||||
for (int i = 0; buf[i] != '\0'; i++) {
|
||||
if (isxdigit(buf[i])) {
|
||||
hex_char_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hex_char_count == 32) { // 128 bits (32 hex characters)
|
||||
unsigned char key1[16] = {0};
|
||||
unsigned char key2[16] = {0};
|
||||
|
||||
char *pEnd;
|
||||
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||
|
||||
u64_to_bytes_be_pc5(K1, &key1[0]);
|
||||
u64_to_bytes_be_pc5(K2, &key1[8]);
|
||||
|
||||
// Reverse key for PC5 (only for 128-bit)
|
||||
for (int i=0;i<16;i++) key2[i] = key1[15-i];
|
||||
|
||||
/* Create key schedule */
|
||||
create_keys_pc5(&ctxpc5, key2, sizeof(key2));
|
||||
ctxpc5.rounds = nbround;
|
||||
|
||||
fprintf(stderr, "DMR BAOFENG AP (PC5) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||
(unsigned long long)K1, (unsigned long long)K2);
|
||||
state->baofeng_ap = 1;
|
||||
|
||||
} else if (hex_char_count == 64) { // 256 bits (64 hex characters)
|
||||
// Remove spaces and store as ASCII string (64 bytes)
|
||||
char ascii_key[65] = {0}; // 64 characters + null terminator
|
||||
int j = 0;
|
||||
for (int i = 0; buf[i] != '\0' && j < 64; i++) {
|
||||
if (isxdigit(buf[i])) {
|
||||
ascii_key[j++] = buf[i];
|
||||
}
|
||||
}
|
||||
ascii_key[64] = '\0';
|
||||
|
||||
/* Create key schedule */
|
||||
create_keys_pc5(&ctxpc5, (unsigned char*)ascii_key, 64);
|
||||
ctxpc5.rounds = nbround;
|
||||
|
||||
fprintf(stderr, "DMR BAOFENG AP (PC5) 256-bit Key: %s with Forced Application\n", ascii_key);
|
||||
state->baofeng_ap = 1;
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Invalid key length. Expected 32 chars (128-bit) or 64 chars (256-bit), got %d hex chars\n", hex_char_count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
404
src/crypt-rc2.c
Normal file
404
src/crypt-rc2.c
Normal file
@@ -0,0 +1,404 @@
|
||||
#include "rc2.h"
|
||||
#include "dsd.h"
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int n) {
|
||||
return ((x << n) | (x >> (63 - n) >> 1)) & 0xffffffffffffffff;
|
||||
}
|
||||
|
||||
void swapbit(uint64_t* internalstate, uint8_t bit) {
|
||||
unsigned char bitB = bit & 1;
|
||||
if (bitB)
|
||||
*internalstate |= bitB;
|
||||
else
|
||||
*internalstate &= (~bitB ^ 1);
|
||||
}
|
||||
|
||||
// MD2 functions
|
||||
void md2_init(MD2State* state) {
|
||||
state->x1 = 0;
|
||||
state->x2 = 0;
|
||||
memset(state->h2, 0, n1);
|
||||
memset(state->h1, 0, n1 * 3);
|
||||
}
|
||||
|
||||
void md2_hashing(MD2State* state, unsigned char t1[], size_t b6) {
|
||||
static unsigned char s4[256] = {
|
||||
13,199,11,67,237,193,164,77,115,184,141,222,73,
|
||||
38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||
119,22,207,35,198,37,171,167,80,30,219,28,213,
|
||||
121,86,29,214,242,6,4,89,162,110,175,19,157,
|
||||
3,88,234,94,144,118,159,239,100,17,182,173,238,
|
||||
68,16,79,132,54,163,52,9,58,57,55,229,192,
|
||||
170,226,56,231,187,158,70,224,233,245,26,47,32,
|
||||
44,247,8,251,20,197,185,109,153,204,218,93,178,
|
||||
212,137,84,174,24,120,130,149,72,180,181,208,255,
|
||||
189,152,18,143,176,60,249,27,227,128,139,243,253,
|
||||
59,123,172,108,211,96,138,10,215,42,225,40,81,
|
||||
65,90,25,98,126,154,64,124,116,122,5,1,168,
|
||||
83,190,131,191,244,240,235,177,155,228,125,66,43,
|
||||
201,248,220,129,188,230,62,75,71,78,34,31,216,
|
||||
254,136,91,114,106,46,217,196,92,151,209,133,51,
|
||||
236,33,252,127,179,69,7,183,105,146,97,39,15,
|
||||
205,112,200,166,223,45,48,246,186,41,148,140,107,
|
||||
76,85,95,194,142,50,49,134,23,135,169,221,210,
|
||||
203,63,165,82,161,202,53,14,206,232,103,102,195,
|
||||
117,250,99,0,74,160,241,2,113
|
||||
};
|
||||
|
||||
int b4 = 0;
|
||||
|
||||
while (b6) {
|
||||
for (; b6 && state->x2 < n1; b6--, state->x2++) {
|
||||
int b5 = t1[b4++];
|
||||
state->h1[state->x2 + n1] = b5;
|
||||
state->h1[state->x2 + (n1 * 2)] = b5 ^ state->h1[state->x2];
|
||||
state->x1 = state->h2[state->x2] ^= s4[b5 ^ state->x1];
|
||||
}
|
||||
|
||||
if (state->x2 == n1) {
|
||||
int b2 = 0;
|
||||
state->x2 = 0;
|
||||
|
||||
for (int b3 = 0; b3 < (n1 + 2); b3++) {
|
||||
for (int b1 = 0; b1 < (n1 * 3); b1++)
|
||||
b2 = state->h1[b1] ^= s4[b2];
|
||||
b2 = (b2 + b3) % 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void md2_end(MD2State* state, unsigned char h4[n1]) {
|
||||
unsigned char h3[n1];
|
||||
int n4 = n1 - state->x2;
|
||||
for (int i = 0; i < n4; i++) h3[i] = n4;
|
||||
md2_hashing(state, h3, n4);
|
||||
md2_hashing(state, state->h2, sizeof(state->h2));
|
||||
for (int i = 0; i < n1; i++) h4[i] = state->h1[i];
|
||||
}
|
||||
|
||||
// RC4 functions
|
||||
uint64_t next(RC4State* state) {
|
||||
uint64_t z = (state->x += 0x9e3779b97f4a7c15);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
void rc4_init(RC4State* state, unsigned char key[]) {
|
||||
int tmp;
|
||||
|
||||
for (state->i_rc4 = 0; state->i_rc4 < 256; state->i_rc4++) {
|
||||
state->array_rc4[state->i_rc4] = state->i_rc4;
|
||||
}
|
||||
|
||||
state->j_rc4 = 0;
|
||||
for (state->i_rc4 = 0; state->i_rc4 < 256; state->i_rc4++) {
|
||||
state->j_rc4 = (state->j_rc4 + state->array_rc4[state->i_rc4] + key[state->i_rc4 % 256]) % 256;
|
||||
tmp = state->array_rc4[state->i_rc4];
|
||||
state->array_rc4[state->i_rc4] = state->array_rc4[state->j_rc4];
|
||||
state->array_rc4[state->j_rc4] = tmp;
|
||||
}
|
||||
state->i_rc4 = 0;
|
||||
state->j_rc4 = 0;
|
||||
}
|
||||
|
||||
unsigned char rc4_output(RC4State* state) {
|
||||
uint8_t rndbyte, decal;
|
||||
int tmp, t;
|
||||
|
||||
state->i_rc4 = (state->i_rc4 + 1) % 256;
|
||||
state->j_rc4 = (state->j_rc4 + state->array_rc4[state->i_rc4]) % 256;
|
||||
tmp = state->array_rc4[state->i_rc4];
|
||||
state->array_rc4[state->i_rc4] = state->array_rc4[state->j_rc4];
|
||||
state->array_rc4[state->j_rc4] = tmp;
|
||||
t = (state->array_rc4[state->i_rc4] + state->array_rc4[state->j_rc4]) % 256;
|
||||
|
||||
|
||||
if (state->xyz == 0) state->bb = next(state);
|
||||
decal = 56 - (8 * state->xyz);
|
||||
rndbyte = (state->bb >> decal) & 0xff;
|
||||
state->xyz++;
|
||||
if (state->xyz == 8) state->xyz = 0;
|
||||
|
||||
if (state->count == 0) {
|
||||
rndbyte = rndbyte ^ state->array_rc4[t];
|
||||
state->count = 1;
|
||||
} else {
|
||||
rndbyte = rndbyte + state->array_rc4[t];
|
||||
state->count = 0;
|
||||
}
|
||||
|
||||
|
||||
return rndbyte;
|
||||
}
|
||||
|
||||
/* Convert 64-bit integer to bytes (big-endian) */
|
||||
static void u64_to_bytes_be(uint64_t val, unsigned char *out) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out[i] = (unsigned char)((val >> (56 - 8 * i)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
// RC2 functions
|
||||
void rc2_keyschedule(RC2State* state) {
|
||||
unsigned i;
|
||||
// Phase 3 - copy to xkey in little-endian order
|
||||
i = 63;
|
||||
do {
|
||||
state->xkey[i] = ((unsigned char *)state->xkey)[2 * i] +
|
||||
(((unsigned char *)state->xkey)[2 * i + 1] << 8);
|
||||
} while (i--);
|
||||
}
|
||||
|
||||
void rc2_encrypt(RC2State* state) {
|
||||
uint16_t x76, x54, x32, x10, i;
|
||||
|
||||
x76 = (state->plain[7] << 8) + state->plain[6];
|
||||
x54 = (state->plain[5] << 8) + state->plain[4];
|
||||
x32 = (state->plain[3] << 8) + state->plain[2];
|
||||
x10 = (state->plain[1] << 8) + state->plain[0];
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
x10 += (x32 & ~x76) + (x54 & x76) + state->xkey[4 * i + 0];
|
||||
x10 = (x10 << 1) + (x10 >> 15 & 1);
|
||||
|
||||
x32 += (x54 & ~x10) + (x76 & x10) + state->xkey[4 * i + 1];
|
||||
x32 = (x32 << 2) + (x32 >> 14 & 3);
|
||||
|
||||
x54 += (x76 & ~x32) + (x10 & x32) + state->xkey[4 * i + 2];
|
||||
x54 = (x54 << 3) + (x54 >> 13 & 7);
|
||||
|
||||
x76 += (x10 & ~x54) + (x32 & x54) + state->xkey[4 * i + 3];
|
||||
x76 = (x76 << 5) + (x76 >> 11 & 31);
|
||||
|
||||
if (i == 4 || i == 10) {
|
||||
x10 += state->xkey[x76 & 63];
|
||||
x32 += state->xkey[x10 & 63];
|
||||
x54 += state->xkey[x32 & 63];
|
||||
x76 += state->xkey[x54 & 63];
|
||||
}
|
||||
}
|
||||
|
||||
state->cipher[0] = (unsigned char)x10;
|
||||
state->cipher[1] = (unsigned char)(x10 >> 8);
|
||||
state->cipher[2] = (unsigned char)x32;
|
||||
state->cipher[3] = (unsigned char)(x32 >> 8);
|
||||
state->cipher[4] = (unsigned char)x54;
|
||||
state->cipher[5] = (unsigned char)(x54 >> 8);
|
||||
state->cipher[6] = (unsigned char)x76;
|
||||
state->cipher[7] = (unsigned char)(x76 >> 8);
|
||||
|
||||
}
|
||||
|
||||
// Main cryptographic functions
|
||||
void create_keys_rc2(CryptoContext* ctx, unsigned char key1[], size_t size1) {
|
||||
unsigned char h4[n1];
|
||||
|
||||
// Initialize MD2 and hash the key
|
||||
md2_init(&ctx->md2);
|
||||
md2_hashing(&ctx->md2, key1, size1);
|
||||
md2_end(&ctx->md2, h4);
|
||||
|
||||
// Copy first 16 bytes to keys
|
||||
for (int i = 0; i < 16; i++) ctx->keys[i] = h4[i];
|
||||
|
||||
// Initialize RC4 with hashed key
|
||||
rc4_init(&ctx->rc4, h4);
|
||||
|
||||
// Initialize RC4 state variables
|
||||
ctx->rc4.x = 0;
|
||||
for (int i = 0; i < 8; i++) ctx->rc4.x = (ctx->rc4.x << 8) + (h4[256 + i] & 0xff);
|
||||
|
||||
ctx->rc4.xyz = 0;
|
||||
ctx->rc4.count = 0;
|
||||
|
||||
// Warm-up RC4
|
||||
for (int i = 0; i < 22000; i++) rc4_output(&ctx->rc4);
|
||||
|
||||
// Generate RC2 keys
|
||||
int k = rc4_output(&ctx->rc4) + 256;
|
||||
for (int i = 0; i < k; i++) rc4_output(&ctx->rc4);
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
ctx->rc2.xkey[i] = (rc4_output(&ctx->rc4) << 8) + rc4_output(&ctx->rc4);
|
||||
}
|
||||
|
||||
// Generate internal zero value
|
||||
k = rc4_output(&ctx->rc4) + 256;
|
||||
for (int i = 0; i < k; i++) rc4_output(&ctx->rc4);
|
||||
|
||||
ctx->internal_zero = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->internal_zero = (ctx->internal_zero << 8) + rc4_output(&ctx->rc4);
|
||||
}
|
||||
|
||||
// Generate RC2 key schedule
|
||||
rc2_keyschedule(&ctx->rc2);
|
||||
}
|
||||
|
||||
void encryption_rc2(CryptoContext* ctx, uint8_t bits[49]) {
|
||||
ctx->internal_state = ctx->internal_zero;
|
||||
|
||||
for (int sso = 0; sso < 49; sso++) {
|
||||
// Prepare plaintext from internal state
|
||||
ctx->rc2.plain[0] = (ctx->internal_state >> 56) & 0xff;
|
||||
ctx->rc2.plain[1] = (ctx->internal_state >> 48) & 0xff;
|
||||
ctx->rc2.plain[2] = (ctx->internal_state >> 40) & 0xff;
|
||||
ctx->rc2.plain[3] = (ctx->internal_state >> 32) & 0xff;
|
||||
ctx->rc2.plain[4] = (ctx->internal_state >> 24) & 0xff;
|
||||
ctx->rc2.plain[5] = (ctx->internal_state >> 16) & 0xff;
|
||||
ctx->rc2.plain[6] = (ctx->internal_state >> 8) & 0xff;
|
||||
ctx->rc2.plain[7] = ctx->internal_state & 0xff;
|
||||
|
||||
// Encrypt with RC2
|
||||
rc2_encrypt(&ctx->rc2);
|
||||
|
||||
// Reconstruct internal state from ciphertext
|
||||
ctx->internal_state = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->internal_state = (ctx->internal_state << 8) + (ctx->rc2.cipher[i] & 0xff);
|
||||
}
|
||||
|
||||
// XOR the bit and update internal state
|
||||
bits[48 - sso] = bits[48 - sso] ^ (ctx->internal_state & 1);
|
||||
ctx->internal_state = rol64(ctx->internal_state, 1);
|
||||
swapbit(&ctx->internal_state, bits[48 - sso]);
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt_rc2(CryptoContext* ctx, uint8_t bits[49]) {
|
||||
uint8_t tempy;
|
||||
ctx->internal_state = ctx->internal_zero;
|
||||
|
||||
|
||||
for (int sso = 0; sso < 49; sso++) {
|
||||
// Prepare plaintext from internal state
|
||||
ctx->rc2.plain[0] = (ctx->internal_state >> 56) & 0xff;
|
||||
ctx->rc2.plain[1] = (ctx->internal_state >> 48) & 0xff;
|
||||
ctx->rc2.plain[2] = (ctx->internal_state >> 40) & 0xff;
|
||||
ctx->rc2.plain[3] = (ctx->internal_state >> 32) & 0xff;
|
||||
ctx->rc2.plain[4] = (ctx->internal_state >> 24) & 0xff;
|
||||
ctx->rc2.plain[5] = (ctx->internal_state >> 16) & 0xff;
|
||||
ctx->rc2.plain[6] = (ctx->internal_state >> 8) & 0xff;
|
||||
ctx->rc2.plain[7] = ctx->internal_state & 0xff;
|
||||
|
||||
// Encrypt with RC2
|
||||
rc2_encrypt(&ctx->rc2);
|
||||
|
||||
// Reconstruct internal state from ciphertext
|
||||
ctx->internal_state = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->internal_state = (ctx->internal_state << 8) + (ctx->rc2.cipher[i] & 0xff);
|
||||
}
|
||||
|
||||
// XOR the bit and update internal state
|
||||
tempy = bits[48 - sso];
|
||||
bits[48 - sso] = bits[48 - sso] ^ (ctx->internal_state & 1);
|
||||
ctx->internal_state = rol64(ctx->internal_state, 1);
|
||||
swapbit(&ctx->internal_state, tempy);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Key creation for Retevis AP */
|
||||
void retevis_rc2_keystream_creation(dsd_state *state, char *input) {
|
||||
|
||||
unsigned char key1[64]; memset(key1, 0, sizeof(key1));
|
||||
unsigned char key2[64]; memset(key2, 0, sizeof(key2));
|
||||
|
||||
char buf[1024];
|
||||
strncpy(buf, input, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
char *pEnd;
|
||||
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||
uint64_t K3 = strtoull(pEnd, &pEnd, 16);
|
||||
uint64_t K4 = strtoull(pEnd, &pEnd, 16);
|
||||
|
||||
if (K3 != 0 || K4 != 0) //256-bit keys loaded as ASCII characters
|
||||
{
|
||||
//start loading K1, K2, K3, and K4 as ASCII to fill 64 bytes of key1
|
||||
int k = 0; uint8_t x = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K1 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K2 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K3 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K4 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "ASCII: ");
|
||||
// for (int i = 0; i < 64; i++)
|
||||
// fprintf (stderr, " %02X", key1[i]);
|
||||
// fprintf (stderr, "\n");
|
||||
|
||||
// Initialize RC2 context
|
||||
static CryptoContext rc2_ctx;
|
||||
create_keys_rc2(&rc2_ctx, key1, 64);
|
||||
|
||||
// Store context in DSD state
|
||||
state->rc2_context = malloc(sizeof(CryptoContext));
|
||||
memcpy(state->rc2_context, &rc2_ctx, sizeof(CryptoContext));
|
||||
|
||||
fprintf(stderr, "DMR RETEVIS AP (RC2) 256-bit Key %016llX%016llX%016llX%016llX with Forced Application\n",
|
||||
(unsigned long long)K1, (unsigned long long)K2, (unsigned long long)K3, (unsigned long long)K4);
|
||||
|
||||
state->retevis_ap = 1;
|
||||
}
|
||||
|
||||
else //128-bit loaded as reverse bytes
|
||||
{
|
||||
|
||||
u64_to_bytes_be(K1, &key1[0]);
|
||||
u64_to_bytes_be(K2, &key1[8]);
|
||||
|
||||
// reverse load the key bytes into key2
|
||||
for (int i=0;i<16;i++)
|
||||
key2[i] = key1[15-i];
|
||||
|
||||
// Initialize RC2 context
|
||||
static CryptoContext rc2_ctx;
|
||||
create_keys_rc2(&rc2_ctx, key2, 16);
|
||||
|
||||
// Store context in DSD state
|
||||
state->rc2_context = malloc(sizeof(CryptoContext));
|
||||
memcpy(state->rc2_context, &rc2_ctx, sizeof(CryptoContext));
|
||||
|
||||
fprintf(stderr, "DMR RETEVIS AP (RC2) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||
(unsigned long long)K1, (unsigned long long)K2);
|
||||
|
||||
state->retevis_ap = 1;
|
||||
}
|
||||
}
|
||||
146
src/crypt-tyt.c
146
src/crypt-tyt.c
@@ -159,28 +159,96 @@ void tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int
|
||||
|
||||
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input)
|
||||
{
|
||||
unsigned char key1[16] = {0};
|
||||
unsigned char key2[16] = {0};
|
||||
|
||||
unsigned char key1[64]; memset(key1, 0, sizeof(key1));
|
||||
unsigned char key2[64]; memset(key2, 0, sizeof(key2));
|
||||
|
||||
char buf[1024];
|
||||
strncpy(buf, input, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
|
||||
char *pEnd;
|
||||
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||
uint64_t K3 = strtoull(pEnd, &pEnd, 16);
|
||||
uint64_t K4 = strtoull(pEnd, &pEnd, 16);
|
||||
|
||||
if (K3 != 0 || K4 != 0) //256-bit keys loaded as ASCII characters
|
||||
{
|
||||
//start loading K1, K2, K3, and K4 as ASCII to fill 64 bytes of key1
|
||||
int k = 0; uint8_t x = 0;
|
||||
|
||||
u64_to_bytes_be(K1, &key1[0]);
|
||||
u64_to_bytes_be(K2, &key1[8]);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K1 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i=0;i<16;i++) key2[i] = key1[15-i];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K2 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
/* Create key schedule */
|
||||
create_keys(&ctx, key2, sizeof(key2));
|
||||
ctx.rounds = nbround;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K3 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
fprintf (stderr,"DMR TYT AP (PC4) 128-bit Key %016llX%016llX with Forced Application\n", (unsigned long long int)K1, (unsigned long long int)K2);
|
||||
state->tyt_ap = 1;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K4 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "ASCII: ");
|
||||
// for (int i = 0; i < 64; i++)
|
||||
// fprintf (stderr, " %02X", key1[i]);
|
||||
// fprintf (stderr, "\n");
|
||||
|
||||
/* Create key schedule */
|
||||
create_keys(&ctx, key1, 64);
|
||||
ctx.rounds = nbround;
|
||||
|
||||
fprintf(stderr, "DMR TYT AP (PC4) 256-bit Key %016llX%016llX%016llX%016llX with Forced Application\n",
|
||||
(unsigned long long)K1, (unsigned long long)K2, (unsigned long long)K3, (unsigned long long)K4);
|
||||
|
||||
state->tyt_ap = 1;
|
||||
}
|
||||
|
||||
else //128-bit loaded as reverse bytes
|
||||
{
|
||||
|
||||
u64_to_bytes_be(K1, &key1[0]);
|
||||
u64_to_bytes_be(K2, &key1[8]);
|
||||
|
||||
// reverse load the key bytes into key2
|
||||
for (int i=0;i<16;i++)
|
||||
key2[i] = key1[15-i];
|
||||
|
||||
/* Create key schedule */
|
||||
create_keys(&ctx, key2, 16);
|
||||
ctx.rounds = nbround;
|
||||
|
||||
fprintf (stderr,"DMR TYT AP (PC4) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||
(unsigned long long int)K1, (unsigned long long int)K2);
|
||||
|
||||
state->tyt_ap = 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -238,4 +306,56 @@ void tyt_ep_aes_keystream_creation(dsd_state * state, char * input)
|
||||
fprintf (stderr,"DMR TYT EP (AES-128) Key %016llX%016llX with Forced Application\n", K1, K2);
|
||||
state->tyt_ep = 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//connect systems 72-bit (9-byte) Extended Encryption //TODO: Move this later
|
||||
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24])
|
||||
{
|
||||
|
||||
char interleaved[72];
|
||||
memset (interleaved, 0, sizeof(interleaved));
|
||||
|
||||
//interleave the frame
|
||||
const int *w, *x, *y, *z;
|
||||
w = rW; x = rX; y = rY; z = rZ;
|
||||
|
||||
for (int8_t i = 0; i < 36; i++)
|
||||
{
|
||||
interleaved[(i*2)+0] = ambe_fr[*w][*x];
|
||||
interleaved[(i*2)+1] = ambe_fr[*y][*z];
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
uint8_t ks_bytes[9]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
uint8_t ks[72]; memset(ks, 0, sizeof(ks));
|
||||
|
||||
//keys are loaded in reverse byte order, stored in state->static_ks_bits[0]
|
||||
for (int i = 0; i < 9; i++)
|
||||
ks_bytes[i] = state->static_ks_bits[0][8-i];
|
||||
|
||||
//convert byte array into a bit array
|
||||
unpack_byte_array_into_bit_array(ks_bytes, ks, 9);
|
||||
|
||||
//apply keystream to interleave
|
||||
for (int8_t i = 0; i < 72; i++)
|
||||
interleaved[i] ^= ks[71-i];
|
||||
|
||||
//deinterleave back into ambe_fr frame
|
||||
w = rW; x = rX; y = rY; z = rZ;
|
||||
int k = 0;
|
||||
for (int8_t i = 0; i < 36; i++)
|
||||
{
|
||||
ambe_fr[*w][*x] = interleaved[k++];
|
||||
ambe_fr[*y][*z] = interleaved[k++];
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
108
src/dmr_block.c
108
src/dmr_block.c
@@ -335,7 +335,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
//The SAP found here is the actual SAP of the message (like a P25 ndary SAP, and can chain together according to ETSI)
|
||||
fprintf (stderr, " - SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string);
|
||||
|
||||
//p_sap 1 on mfid 10 (moto) has been observed as the first block of LRRP data (unique fixed format?)
|
||||
//p_sap 1 on mfid 10 MNIS Header
|
||||
if (p_mfid == 0x10 && p_sap == 1)
|
||||
{
|
||||
//add the header to the first 10 bytes of the storage (sans this header's CRC)
|
||||
@@ -365,7 +365,42 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
}
|
||||
|
||||
//Start Setting DMR Data Packet Encryption Variables
|
||||
if (p_sap != 1 && p_mfid == 0x10)
|
||||
if (p_sap != 1 && p_mfid == 0x77)
|
||||
{
|
||||
|
||||
fprintf (stderr, "\n Vertex Standard PDU ENC Header:");
|
||||
fprintf (stderr, " MFID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8));
|
||||
|
||||
//Unsure of how similar this is to the DMRA Enc Header, but using
|
||||
//guess work and best judgment from single sample of Vertex Enhanced
|
||||
|
||||
//main issue is, I don't know if the 0x01 signalled is a key id (which is known to be 0x01)
|
||||
//or if it is an encryption alg id (alg may have to be inferred based on what is loaded in radio)
|
||||
|
||||
//set to 0x100 so it won't trigger any weird flags, but still has a non-zero value to be checked later
|
||||
if (state->currentslot == 0) state->dmr_so = 0x100;
|
||||
else state->dmr_soR = 0x100;
|
||||
|
||||
if (state->currentslot == 0)
|
||||
state->payload_keyid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8);
|
||||
else state->payload_keyidR = (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8);
|
||||
fprintf (stderr, " Key ID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8));
|
||||
|
||||
//going to use algid of 0x7 to signal a vertex standard enc method
|
||||
if (state->currentslot == 0)
|
||||
state->payload_algid = 0x7;
|
||||
else state->payload_algidR = 0x7;
|
||||
|
||||
//unknown if MI, or IV is present on this header (need the AES256 Vertex PDU to compare)
|
||||
if (state->currentslot == 0)
|
||||
state->payload_mi = (unsigned long long int)ConvertBitIntoBytes(&dheader_bits[48], 32);
|
||||
else state->payload_miR = (unsigned long long int)ConvertBitIntoBytes(&dheader_bits[48], 32);
|
||||
|
||||
//reset ks start value
|
||||
state->data_ks_start[slot] = 0;
|
||||
|
||||
}
|
||||
else if (p_sap != 1 && p_mfid == 0x10)
|
||||
{
|
||||
|
||||
//check ENC bit, assuming this is an ENC bit, or SVC OPT like thing (or could be an opcode for the rest of the extended header)
|
||||
@@ -376,7 +411,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
else state->dmr_soR = 0x100;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n PDU ENC Header:");
|
||||
fprintf (stderr, "\n DMRA PDU ENC Header:");
|
||||
fprintf (stderr, " MFID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8));
|
||||
fprintf (stderr, " ENC: %X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[20], 4));
|
||||
|
||||
@@ -1007,6 +1042,21 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
if (memcmp(kaes, empt, sizeof(kaes)) != 0) akl = 1;
|
||||
}
|
||||
|
||||
//if still not akl, see if there is anything manually loaded into K1, K2, K3, K4 instead
|
||||
if (akl == 0)
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
kaes[i+0] = (state->K1) >> (56-(i*8)) & 0xFF;
|
||||
kaes[i+8] = (state->K2) >> (56-(i*8)) & 0xFF;
|
||||
kaes[i+16] = (state->K3) >> (56-(i*8)) & 0xFF;
|
||||
kaes[i+24] = (state->K4) >> (56-(i*8)) & 0xFF;
|
||||
}
|
||||
|
||||
//if kaes is loaded with a key, then flag on the key loaded variable
|
||||
if (memcmp(kaes, empt, sizeof(kaes)) != 0) akl = 1;
|
||||
}
|
||||
|
||||
if (R == 0 && state->R != 0) R = state->R;
|
||||
|
||||
//easier to manually load up rather than make a loop (RC4)
|
||||
@@ -1022,19 +1072,25 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
|
||||
//print alg/key and value if loaded
|
||||
fprintf (stderr, "\n PDU ALG: %02X; Key ID: %02X;", alg, kid);
|
||||
if (alg != 0) fprintf (stderr, " MI(32): %08llX;", mi);
|
||||
if (alg != 0 && mi != 0) fprintf (stderr, " MI(32): %08llX;", mi);
|
||||
if (alg == 0) fprintf (stderr, " Moto BP;");
|
||||
if (alg == 1) fprintf (stderr, " RC4;");
|
||||
if (alg == 2) fprintf (stderr, " DES;");
|
||||
if (alg == 4) fprintf (stderr, " AES128;");
|
||||
if (alg == 5) fprintf (stderr, " AES256;");
|
||||
if (alg == 7) fprintf (stderr, " VTX STD;");
|
||||
if (R && alg != 0) fprintf (stderr, " Key: %010llX;", R);
|
||||
|
||||
//generate 128-bit IV from 32-bit MI
|
||||
//expand 32-bit MI to 128-bit IV for AES mode data decryption
|
||||
//we only want to do this at the moment of keystream generation
|
||||
if (alg == 5)
|
||||
if (alg == 4 || alg == 5)
|
||||
{
|
||||
//for the LFSR128d function to show the correct alg
|
||||
if (state->currentslot == 0)
|
||||
state->payload_algid += 0x20;
|
||||
else state->payload_algidR += 0x20;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
LFSR128d(state);
|
||||
if (state->currentslot == 0)
|
||||
@@ -1049,30 +1105,54 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
if (alg == 5 && akl == 1) //AES-256
|
||||
else if (alg == 5 && akl == 1 && mi != 0) //AES-256 OFB
|
||||
{
|
||||
int nblocks = (state->data_byte_ctr[slot] / 16) + 1;
|
||||
aes_ofb_keystream_output (maes, kaes, ob, 2, nblocks);
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
else if (alg == 5 && akl == 1 && mi == 0) //AES-256 ECB (CCR without an IV)
|
||||
{
|
||||
//void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de)
|
||||
int nblocks = (state->data_byte_ctr[slot] / 16) + 0; //was +1
|
||||
for (i = 0; i < nblocks; i++)
|
||||
{
|
||||
aes_ecb_bytewise_payload_crypt(state->dmr_pdu_sf[slot]+start, kaes, state->dmr_pdu_sf[slot]+start, 2, 0);
|
||||
start += 16;
|
||||
}
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
//other algs available, not sure if others will be used in any DMRA offerings
|
||||
if (alg == 2 && R != 0) //Tait DES
|
||||
else if (alg == 2 && R != 0) //Tait DES
|
||||
{
|
||||
int nblocks = (state->data_byte_ctr[slot] / 8) + 1;
|
||||
des_multi_keystream_output (mi, R, ob, 1, nblocks);
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
if (alg == 4 && akl == 1) //AES-128
|
||||
else if (alg == 4 && akl == 1 && mi != 0) //AES-128 OFB
|
||||
{
|
||||
int nblocks = (state->data_byte_ctr[slot] / 16) + 1;
|
||||
aes_ofb_keystream_output (maes, kaes, ob, 0, nblocks);
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
else if (alg == 4 && akl == 1 && mi == 0) //AES-128 ECB (CCR without an IV)
|
||||
{
|
||||
//void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de)
|
||||
int nblocks = (state->data_byte_ctr[slot] / 16) + 0; //was +1
|
||||
for (i = 0; i < nblocks; i++)
|
||||
{
|
||||
aes_ecb_bytewise_payload_crypt(state->dmr_pdu_sf[slot]+start, kaes, state->dmr_pdu_sf[slot]+start, 0, 0);
|
||||
start += 16;
|
||||
}
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
//NOTE: Observed that keystream should not be applied to pad bytes or CRC
|
||||
//apply keystream here, only if alg is 1 or 4 AND key is available!
|
||||
//apply keystream here, only if key is available and keystream created, not ECB.
|
||||
if (alg == 1 && R != 0)
|
||||
{
|
||||
for (i = 0; i < end; i++)
|
||||
@@ -1084,15 +1164,17 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
for (i = 0; i < end; i++)
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
|
||||
}
|
||||
else if (alg == 4 && akl != 0)
|
||||
|
||||
else if (alg == 4 && akl != 0 && mi != 0)
|
||||
{
|
||||
for (i = 0; i < end; i++)
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[(i+16)%3096];
|
||||
}
|
||||
else if (alg == 5 && akl != 0)
|
||||
|
||||
else if (alg == 5 && akl != 0 && mi != 0)
|
||||
{
|
||||
for (i = 0; i < end; i++)
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[(i+16)%3096];
|
||||
}
|
||||
|
||||
//BP key application
|
||||
|
||||
14
src/dmr_bs.c
14
src/dmr_bs.c
@@ -502,6 +502,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||
}
|
||||
|
||||
if (state->csi_ee == 1)
|
||||
{
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||
}
|
||||
|
||||
#ifdef PRINT_AMBE72
|
||||
ambe2_codeword_print_i(opts, ambe_fr);
|
||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||
@@ -954,6 +961,13 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||
}
|
||||
|
||||
if (state->csi_ee == 1)
|
||||
{
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||
}
|
||||
|
||||
#ifdef PRINT_AMBE72
|
||||
ambe2_codeword_print_i(opts, ambe_fr);
|
||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||
|
||||
@@ -72,6 +72,15 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
so ^= 0x40;
|
||||
}
|
||||
|
||||
//Kirisun
|
||||
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40
|
||||
{
|
||||
//disable late entry for DMRA, Flag 3 if encrypted, 0 if not
|
||||
if (so & 0x40)
|
||||
opts->dmr_le = 3;
|
||||
else opts->dmr_le = 0;
|
||||
}
|
||||
|
||||
//read ahead a little to get this for the xpt flag
|
||||
if (*IrrecoverableErrors == 0 && flco == 0x09 && fid == 0x68)
|
||||
{
|
||||
@@ -310,8 +319,8 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
}
|
||||
|
||||
//unknown other manufacturer or OTA ENC, etc.
|
||||
//removed tait from the list, added hytera 0x08
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08 && is_kenwood_sc == 0)
|
||||
//removed tait from the list, added hytera 0x08, added Kirisun and KW Scrambler LC
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08 && fid != 0x0A && is_kenwood_sc == 0)
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KYEL);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KYEL);
|
||||
@@ -654,6 +663,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
}
|
||||
|
||||
//should rework this back into the upper portion
|
||||
if (fid == 0x0A) fprintf (stderr, "Kirisun ");
|
||||
if (fid == 0x68) fprintf (stderr, "Hytera ");
|
||||
if (is_xpt) fprintf (stderr, "XPT ");
|
||||
if (fid == 0x68 && flco == 0x00)
|
||||
|
||||
90
src/dmr_le.c
90
src/dmr_le.c
@@ -14,23 +14,6 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
//enforce RC4 due to missing PI header, but with valid SVC Opts
|
||||
//ideally, this would be handled by VC-F single burst, but its not fully reliable compared to this
|
||||
//due to multiple signalling occurring inside of it, depending on system type
|
||||
if (state->M == 0x21)
|
||||
{
|
||||
if (slot == 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
state->payload_algid = 0x21;
|
||||
state->payload_keyid = 0xFF;
|
||||
}
|
||||
if (slot == 1 && state->dmr_soR & 0x40)
|
||||
{
|
||||
state->payload_algidR = 0x21;
|
||||
state->payload_keyidR = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//collect our fragments and place them into storage
|
||||
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
|
||||
state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4);
|
||||
@@ -236,6 +219,23 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
if (state->payload_algid == 0x35 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
{
|
||||
state->DMRvcL = 0;
|
||||
state->payload_mi = kirisun_lfsr(state->payload_mi);
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Slot 1");
|
||||
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algid, state->payload_keyid);
|
||||
fprintf (stderr, " MI(32): %08llX;", state->payload_mi);
|
||||
fprintf (stderr, " Kirisun");
|
||||
if (state->payload_algid == 0x36)
|
||||
fprintf (stderr, " Advanced;");
|
||||
else if (state->payload_algid == 0x37)
|
||||
fprintf (stderr, " Universal;");
|
||||
else fprintf (stderr, " Encryption;");
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
@@ -266,6 +266,23 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
if (state->payload_algidR == 0x35 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
||||
{
|
||||
state->DMRvcR = 0;
|
||||
state->payload_miR = kirisun_lfsr(state->payload_miR);
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Slot 2");
|
||||
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algidR, state->payload_keyidR);
|
||||
fprintf (stderr, " MI(32): %08llX;", state->payload_miR);
|
||||
fprintf (stderr, " Kirisun");
|
||||
if (state->payload_algidR == 0x36)
|
||||
fprintf (stderr, " Advanced;");
|
||||
else if (state->payload_algidR == 0x37)
|
||||
fprintf (stderr, " Universal;");
|
||||
else fprintf (stderr, " Encryption;");
|
||||
fprintf (stderr, "%s\n", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -390,6 +407,41 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
//NOTE: on above, I belive that we need to check by opcode as well, as a CRC3 can have multiple collisions
|
||||
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
|
||||
|
||||
//Kirisun Placeholder
|
||||
if (opts->dmr_le == 3)
|
||||
{
|
||||
if (irr_err != 0)
|
||||
{
|
||||
uint32_t sbrcpl = 0;
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
sbrcpl = sbrcpl << 1;
|
||||
sbrcpl |= sbrc_interleaved[i] & 1;
|
||||
}
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s SLOT %d SB/RC (FEC ERR) E:%d; I:%08X D:%03X; %s ", KRED, slot+1, irr_err, sbrcpl, sbrc_hex, KNRM);
|
||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||
}
|
||||
else if (irr_err == 0 && sbrc_hex != 0) //first batch had sbrc_hex 0x5F1, second batch had 0x5E1 instead, what changed?
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot %d", state->currentslot+1);
|
||||
fprintf (stderr, " DMR LE SB Kirisun Encryption Identifier;");
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
if (state->payload_algid == 0 && state->dmr_so & 0x40)
|
||||
state->payload_algid = 0x35; //placeholder value
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state->payload_algidR == 0 && state->dmr_soR & 0x40)
|
||||
state->payload_algidR = 0x35; //placeholder value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->dmr_le == 1)
|
||||
{
|
||||
if (irr_err != 0)
|
||||
@@ -466,7 +518,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
if (state->dmr_so & 0x40 && key != 0 && alg != 0)
|
||||
{
|
||||
//if we aren't forcing a particular alg or privacy key set
|
||||
if (state->M == 0)
|
||||
if (state->forced_alg_id == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
@@ -492,7 +544,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
if (state->dmr_soR & 0x40 && key != 0 && alg != 0)
|
||||
{
|
||||
//if we aren't forcing a particular alg or privacy key set
|
||||
if (state->M == 0)
|
||||
if (state->forced_alg_id == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
|
||||
24
src/dmr_ms.c
24
src/dmr_ms.c
@@ -167,6 +167,16 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//Kirisun Check VC-F for Enc Identifiers -- has bad fec, unless its loaded differently
|
||||
//SEE: https://patents.google.com/patent/CN102307075A/en?q=(kirisun)&q=(dmr)&oq=kirisun
|
||||
// if (opts->dmr_le == 3 && vc == 6)
|
||||
// {
|
||||
// bool kokay = 0;
|
||||
// // kokay = Golay_24_12_decode(syncdata);
|
||||
// unsigned long long int kirisun = (unsigned long long int)ConvertBitIntoBytes(&syncdata[0], 48);
|
||||
// fprintf (stderr, "Kiri: %012llX; Golay Okay: %d; \n", kirisun, kokay);
|
||||
// }
|
||||
|
||||
for(i = 0; i < 8; i++) emb_pdu[i + 0] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
||||
|
||||
@@ -253,6 +263,13 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||
}
|
||||
|
||||
if (state->csi_ee == 1)
|
||||
{
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||
}
|
||||
|
||||
#ifdef PRINT_AMBE72
|
||||
ambe2_codeword_print_i(opts, ambe_fr);
|
||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||
@@ -564,6 +581,13 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||
}
|
||||
|
||||
if (state->csi_ee == 1)
|
||||
{
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||
}
|
||||
|
||||
#ifdef PRINT_AMBE72
|
||||
ambe2_codeword_print_i(opts, ambe_fr);
|
||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||
|
||||
@@ -482,6 +482,34 @@ void decode_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t *
|
||||
sprintf (state->dmr_lrrp_gps[slot], "ETSI TMS SRC: %d; DST: %d; ", src24, dst24);
|
||||
utf16_to_text(state, 1, len, input+28);
|
||||
}
|
||||
//Vertex Standard TMS Port
|
||||
else if (port1 == 5007 && port2 == 5007)
|
||||
{
|
||||
|
||||
//get pad amount to see where to stop parsing UTF16 text
|
||||
int pad = state->data_block_poc[slot];
|
||||
|
||||
//sanity check
|
||||
if (len > (50+pad))
|
||||
len = len - pad - 50;
|
||||
|
||||
fprintf (stderr, "VTX STD TMS; ");
|
||||
|
||||
//+28, get 9 bytes for unknown "header" information
|
||||
//unknown elements 0E0002000000000000, could include a len value or type (utf-16, utf-8, is07?)
|
||||
//the sample has a len of 8 utf-16 chars, only way to get that is on the 2 if not byte aligned (1000)
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
// fprintf (stderr, "Len: %03d; ", len);
|
||||
fprintf (stderr, "??: ");
|
||||
for (int i = 0; i < 9; i++)
|
||||
fprintf (stderr, "%02X", input[i+28]);
|
||||
fprintf (stderr, "; Text: ");
|
||||
}
|
||||
|
||||
sprintf (state->dmr_lrrp_gps[slot], "VTX TMS SRC: %d; DST: %d; ", src24, dst24);
|
||||
utf16_to_text(state, 1, len, input+49);
|
||||
}
|
||||
else if (port1 == 5017 && port2 == 5017)
|
||||
{
|
||||
//sanity check
|
||||
|
||||
92
src/dmr_pi.c
92
src/dmr_pi.c
@@ -12,7 +12,6 @@
|
||||
|
||||
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||
{
|
||||
UNUSED2(opts, CRCCorrect);
|
||||
|
||||
uint8_t MFID = PI_BYTE[1];
|
||||
|
||||
@@ -26,6 +25,57 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
}
|
||||
|
||||
if (MFID == 0x0A && CRCCorrect == 1) //Kirisun
|
||||
{
|
||||
uint8_t so = PI_BYTE[2]; //in VLC and PI, this byte is 0x40, so thinking this could be SVC_OPT
|
||||
uint8_t alg = PI_BYTE[0]; //observed 0x36 and 0x37 for Kirisun Advanced and Universal Privacy
|
||||
// uint8_t kid = PI_BYTE[2]; //user info conveyed there is only 16 allotments for Key, and keys are channel specific, so no key id value
|
||||
uint32_t target = ((unsigned long long int)PI_BYTE[7] << 16) | ((unsigned long long int)PI_BYTE[8] << 8) | ((unsigned long long int)PI_BYTE[9] << 0);
|
||||
|
||||
//TODO: Use ALG and TGT value here to produce a key id via hashing it
|
||||
uint8_t hash = alg * target % 256; //more complex hash later (honestly, probably not)
|
||||
|
||||
//MI only appears to be 32-bit
|
||||
uint32_t mi = ((uint32_t)PI_BYTE[3] << 24) | ((uint32_t)PI_BYTE[4] << 16) |
|
||||
((uint32_t)PI_BYTE[5] << 8) | ((uint32_t)PI_BYTE[6] << 0);
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->dmr_so = so;
|
||||
state->payload_algid = alg;
|
||||
state->payload_keyid = hash;
|
||||
state->payload_mi = mi;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmr_soR = so;
|
||||
state->payload_algidR = alg;
|
||||
state->payload_keyidR = hash;
|
||||
state->payload_miR = mi;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot %d", state->currentslot+1);
|
||||
fprintf (stderr, " DMR PI H- ALG ID: %02X; KEY ID: %02X; MI(32): %08X;", alg, hash, mi);
|
||||
|
||||
fprintf (stderr, " Kirisun ");
|
||||
if (alg == 0x36)
|
||||
fprintf (stderr, "Advanced;");
|
||||
else if (alg == 0x37)
|
||||
fprintf (stderr, "Universal;");
|
||||
else fprintf (stderr, "Encryption;");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//disable late entry for DMRA, Flag 3 for future check of VC-F 48-bit region with Golay 24,12 Encoding
|
||||
//SEE: https://patents.google.com/patent/CN102307075A/en?q=(kirisun)&q=(dmr)&oq=kirisun
|
||||
//tested patent above with information provided, VC-F had a SB, but the 48-bit
|
||||
//full value yielded bad Golay results, and user submitted info contradicts this patent for samples provided
|
||||
//Late Entry MI does appear to work, however, and reports a good CRC for that as well,
|
||||
//reverse engineered LFSR for Kirisun lines up with the late entry for 32-bit MI values.
|
||||
opts->dmr_le = 3;
|
||||
|
||||
}
|
||||
|
||||
if (MFID == 0x68) //Hytera Enhanced
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
@@ -423,13 +473,13 @@ unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len)
|
||||
{
|
||||
uint8_t bit = (mi[i] >> 7) & 1;
|
||||
mi[i] <<= 1;
|
||||
if (bit) mi[i] ^= taps[i%5];
|
||||
if (bit) mi[i] ^= taps[i%len];
|
||||
mi[i] |= bit;
|
||||
|
||||
}
|
||||
|
||||
unsigned long long int mi_value = 0;
|
||||
for (uint8_t i = 0; i < 5; i++)
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
mi_value <<= 8;
|
||||
mi_value |= mi[i];
|
||||
@@ -470,4 +520,38 @@ void hytera_enhanced_alg_refresh(dsd_state * state)
|
||||
if (state->currentslot == 0)
|
||||
state->payload_mi = mi_value;
|
||||
else state->payload_miR = mi_value;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t kirisun_lfsr(unsigned long long int mi)
|
||||
{
|
||||
|
||||
uint32_t taps = 0xD459C4F1;
|
||||
uint32_t lfsr = (uint32_t)mi;
|
||||
uint32_t new_mi = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
||||
uint8_t byte = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint32_t temp = (lfsr << 1);
|
||||
uint8_t msb = (lfsr >> 31) & 1;
|
||||
|
||||
if (msb)
|
||||
{
|
||||
byte |= (1 << j);
|
||||
lfsr = temp ^ taps;
|
||||
}
|
||||
else lfsr = temp; //was previously temp ^ 1, but that isn't a primitive
|
||||
}
|
||||
|
||||
new_mi <<=8;
|
||||
new_mi |= byte;
|
||||
|
||||
}
|
||||
|
||||
return new_mi;
|
||||
|
||||
}
|
||||
|
||||
@@ -794,22 +794,18 @@ void dmr_talker_alias_lc_decode (dsd_opts * opts, dsd_state * state, uint8_t slo
|
||||
}
|
||||
else if (char_size == 16)
|
||||
{
|
||||
int ptr = 0;
|
||||
setlocale(LC_ALL, ""); //needed when encoded alias contains Chinese (or probably any non-roman charset that isn't default on users terminal)
|
||||
for (i = 0; i < end; i++)
|
||||
{
|
||||
uint16_t character = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][(i*16)], 16);
|
||||
char ch[2]; ch[0] = character & 0xFF; ch[1] = 0;
|
||||
|
||||
if (character >= 0x20 && character != 0x7F)
|
||||
fprintf (stderr, "%lc", character);
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
if (character == 0)
|
||||
strcat (alias_string, " ");
|
||||
else if (character >= 0x20 && character <= 0xFE)
|
||||
strcat (alias_string, ch);
|
||||
else
|
||||
strcat (alias_string, "*");
|
||||
//Encode to UTF-8
|
||||
ptr += utf8_encode(character, alias_string+ptr);
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " [%04X], ", character);
|
||||
|
||||
@@ -137,9 +137,11 @@ void openPulseInput(dsd_opts * opts)
|
||||
lt.maxlength = -1;
|
||||
lt.prebuf = -1;
|
||||
lt.tlength = -1;
|
||||
if (opts->m17encoder == 1)
|
||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err);
|
||||
else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||
// if (opts->m17encoder == 1)
|
||||
// opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err);
|
||||
// else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||
|
||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
||||
encL = 0;
|
||||
}
|
||||
}
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
{
|
||||
//going to need a better check for this later on, or seperated keys or something
|
||||
if (state->aes_key_loaded[0] == 1)
|
||||
@@ -126,7 +126,7 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
||||
encR = 0;
|
||||
}
|
||||
}
|
||||
else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||
else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
||||
{
|
||||
//going to need a better check for this later on, or seperated keys or something
|
||||
if (state->aes_key_loaded[1] == 1)
|
||||
@@ -716,7 +716,7 @@ void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state)
|
||||
encL = 0;
|
||||
}
|
||||
}
|
||||
else if (state->payload_algid == 0x84 || state->payload_algid == 0x89 || state->nxdn_cipher_type == 0x3)
|
||||
else if (state->payload_algid == 0x84 || state->payload_algid == 0x89 || state->nxdn_cipher_type == 0x3 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
{
|
||||
if (state->aes_key_loaded[0] == 1)
|
||||
{
|
||||
@@ -1131,7 +1131,7 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
encL = 0;
|
||||
}
|
||||
}
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
{
|
||||
//going to need a better check for this later on, or seperated keys or something
|
||||
if (state->aes_key_loaded[0] == 1)
|
||||
@@ -1157,7 +1157,7 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
encR = 0;
|
||||
}
|
||||
}
|
||||
else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||
else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
||||
{
|
||||
//going to need a better check for this later on, or seperated keys or something
|
||||
if (state->aes_key_loaded[1] == 1)
|
||||
|
||||
@@ -695,7 +695,7 @@ void watchdog_event_current (dsd_opts * opts, dsd_state * state, uint8_t slot)
|
||||
|
||||
if (state->ea_mode == 1)
|
||||
{
|
||||
sprintf (event_string, "%s %s %s TGT: %07d; SRC: %07d; LCN: %02d; SITE: %d:%d.%04X; %s;", datestr, timestr, sys_string, target_id, source_id, channel, sys_id1, sys_id2, sys_id3, sup_str);
|
||||
sprintf (event_string, "%s %s %s TGT: %07d; SRC: %07d; LCN: %02d; SITE: %d:%d.%04X; %s; ", datestr, timestr, sys_string, target_id, source_id, channel, sys_id1, sys_id2, sys_id3, sup_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -262,21 +262,10 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
processYSF(opts, state);
|
||||
return;
|
||||
}
|
||||
//M17
|
||||
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) ||
|
||||
(state->synctype == 76) || (state->synctype == 77) || (state->synctype == 86) || (state->synctype == 87) ||
|
||||
(state->synctype == 99) || (state->synctype == 98) )
|
||||
//M17 STR
|
||||
else if (state->synctype == 16)
|
||||
{
|
||||
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
||||
skipDibit(opts, state, 8); //skip dibits to prime the demodulator
|
||||
else if (state->synctype == 16 || state->synctype == 17)
|
||||
processM17STR(opts, state);
|
||||
else if (state->synctype == 76 || state->synctype == 77) {} //Not available yet
|
||||
// processM17BRT(opts, state); //Not available yet
|
||||
else if (state->synctype == 86 || state->synctype == 87)
|
||||
processM17PKT(opts, state);
|
||||
else
|
||||
processM17LSF(opts, state);
|
||||
processM17STR(opts, state);
|
||||
return;
|
||||
}
|
||||
//P25 P2
|
||||
|
||||
@@ -162,7 +162,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
char synctest20[21]; //YSF
|
||||
char synctest48[49]; //EDACS
|
||||
char synctest8[9]; //M17
|
||||
char synctest16[17]; //M17 Preamble
|
||||
char modulation[8];
|
||||
char *synctest_p;
|
||||
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
||||
@@ -208,9 +207,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
t = 0;
|
||||
synctest10[10] = 0;
|
||||
synctest[24] = 0;
|
||||
synctest8[8] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin)
|
||||
synctest8[8] = 0;
|
||||
synctest12[12] = 0;
|
||||
synctest16[16] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin)
|
||||
synctest48[48] = 0;
|
||||
synctest32[32] = 0;
|
||||
synctest20[20] = 0;
|
||||
@@ -566,139 +564,24 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
//end YSF sync
|
||||
|
||||
//M17 Sync -- Just STR and LSF for now
|
||||
strncpy(synctest16, (synctest_p - 15), 16);
|
||||
//M17 Sync -- Just STR
|
||||
strncpy(synctest8, (synctest_p - 7), 8);
|
||||
if(opts->frame_m17 == 1)
|
||||
{
|
||||
//preambles will skip dibits in an attempt to prime the
|
||||
//demodulator but not attempt any decoding
|
||||
if (strcmp(synctest8, M17_PRE) == 0)
|
||||
if (strcmp(synctest8, M17_STR) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 16)
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 PREAMBLE", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 98;
|
||||
fprintf (stderr, "\n");
|
||||
return (98);
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_PIV) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "-M17 PREAMBLE", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 99;
|
||||
fprintf (stderr, "\n");
|
||||
return (99);
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_PKT) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 PKT", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 86 || state->lastsynctype == 8)
|
||||
{
|
||||
state->lastsynctype = 86;
|
||||
return (86);
|
||||
}
|
||||
state->lastsynctype = 86;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
// else //unknown, -BRT?
|
||||
// {
|
||||
// printFrameSync (opts, state, "-M17 BRT", synctest_pos + 1, modulation);
|
||||
// state->carrier = 1;
|
||||
// state->offset = synctest_pos;
|
||||
// state->max = ((state->max) + lmax) / 2;
|
||||
// state->min = ((state->min) + lmin) / 2;
|
||||
// if (state->lastsynctype == 77)
|
||||
// {
|
||||
// state->lastsynctype = 77;
|
||||
// return (77);
|
||||
// }
|
||||
// state->lastsynctype = 77;
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
}
|
||||
else if (strcmp(synctest8, M17_STR) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 16 || state->lastsynctype == 8)
|
||||
{
|
||||
state->lastsynctype = 16;
|
||||
return (16);
|
||||
}
|
||||
state->lastsynctype = 16;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printFrameSync (opts, state, "-M17 LSF", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 99)
|
||||
{
|
||||
state->lastsynctype = 9;
|
||||
return (9);
|
||||
}
|
||||
state->lastsynctype = 9;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_LSF) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "-M17 STR", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 17 || state->lastsynctype == 9)
|
||||
{
|
||||
state->lastsynctype = 17;
|
||||
return (17);
|
||||
}
|
||||
state->lastsynctype = 17;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 LSF", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 98)
|
||||
{
|
||||
state->lastsynctype = 8;
|
||||
return (8);
|
||||
}
|
||||
state->lastsynctype = 8;
|
||||
fprintf (stderr, "\n");
|
||||
return (16);
|
||||
}
|
||||
state->lastsynctype = 16;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
//end M17
|
||||
|
||||
377
src/dsd_main.c
377
src/dsd_main.c
@@ -538,7 +538,6 @@
|
||||
//M17 Storage
|
||||
memset (state->m17_lsf, 0, sizeof(state->m17_lsf));
|
||||
memset (state->m17_pkt, 0, sizeof(state->m17_pkt));
|
||||
state->m17_pbc_ct = 0;
|
||||
state->m17_str_dt = 9;
|
||||
|
||||
state->m17_dst = 0;
|
||||
@@ -552,13 +551,18 @@
|
||||
state->m17_enc = 0;
|
||||
state->m17_enc_st = 0;
|
||||
memset(state->m17_meta, 0, sizeof(state->m17_meta));
|
||||
|
||||
//misc str storage
|
||||
// sprintf (state->str50a, "%s", "");
|
||||
// memset (state->str50b, 0, 50*sizeof(char));
|
||||
// memset (state->str50c, 0, 50*sizeof(char));
|
||||
// memset (state->m17sms, 0, 800*sizeof(char));
|
||||
// sprintf (state->m17dat, "%s", "");
|
||||
memset(state->m17_aes_iv, 0, sizeof(state->m17_aes_iv));
|
||||
|
||||
memset(state->m17_text_string, 0, sizeof(state->m17_text_string));
|
||||
memset(state->m17_gnss_string, 0, sizeof(state->m17_gnss_string));
|
||||
memset(state->m17_data_string, 0, sizeof(state->m17_data_string));
|
||||
memset(state->m17_meta_string, 0, sizeof(state->m17_meta_string));
|
||||
sprintf (state->m17_text_string, "%s", "");
|
||||
sprintf (state->m17_gnss_string, "%s", "");
|
||||
sprintf (state->m17_data_string, "%s", "");
|
||||
sprintf (state->m17_meta_string, "%s", "");
|
||||
|
||||
state->m17_viterbi_err = 0.0f;
|
||||
|
||||
//set float temp buffer to baseline
|
||||
memset (state->audio_out_temp_buf, 0.0f, sizeof(state->audio_out_temp_buf));
|
||||
@@ -674,15 +678,10 @@
|
||||
opts->uvquality = 3;
|
||||
opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this
|
||||
opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this
|
||||
opts->inverted_m17 = 0; //samples from M17_Education seem to all be positive polarity (same from m17-tools programs)
|
||||
opts->mod_threshold = 26;
|
||||
opts->ssize = 128; //36 default, max is 128, much cleaner data decodes on Phase 2 cqpsk at max
|
||||
opts->msize = 1024; //15 default, max is 1024, much cleaner data decodes on Phase 2 cqpsk at max
|
||||
opts->playfiles = 0;
|
||||
opts->m17encoder = 0;
|
||||
opts->m17encoderbrt = 0;
|
||||
opts->m17encoderpkt = 0;
|
||||
opts->m17decoderip = 0;
|
||||
opts->delay = 0;
|
||||
opts->use_cosine_filter = 1;
|
||||
opts->unmute_encrypted_p25 = 0;
|
||||
@@ -762,12 +761,6 @@
|
||||
opts->udp_portno = 23456; //default port, same os OP25's sockaudio.py
|
||||
sprintf (opts->udp_hostname, "%s", "127.0.0.1");
|
||||
|
||||
//M17 UDP Port and hostname
|
||||
opts->m17_use_ip = 0; //if enabled, open UDP and broadcast IP frame
|
||||
opts->m17_portno = 17000; //default is 17000
|
||||
opts->m17_udp_sock = 0; //actual UDP socket for M17 to send to
|
||||
sprintf (opts->m17_hostname, "%s", "127.0.0.1");
|
||||
|
||||
//tcp input options
|
||||
opts->tcp_sockfd = 0;
|
||||
opts->tcp_portno = 7355; //default favored by SDR++
|
||||
@@ -1041,7 +1034,7 @@
|
||||
state->K2 = 0;
|
||||
state->K3 = 0;
|
||||
state->K4 = 0;
|
||||
state->M = 0; //force key priority over settings from fid/so
|
||||
state->forced_alg_id = 0; //force key priority over settings from fid/so
|
||||
|
||||
state->dmr_stereo = 0; //1, or 0?
|
||||
state->dmrburstL = 17; //initialize at higher value than possible
|
||||
@@ -1064,6 +1057,9 @@
|
||||
state->tyt_ap = 0;
|
||||
state->tyt_bp = 0;
|
||||
state->tyt_ep = 0;
|
||||
state->retevis_ap = 0;
|
||||
state->baofeng_ap = 0;
|
||||
state->csi_ee = 0;
|
||||
|
||||
state->ken_sc = 0;
|
||||
state->any_bp = 0;
|
||||
@@ -1213,6 +1209,7 @@
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
state->nxdn_alias_block_number = 0;
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
state->nxdn_pn95_seed = 228; //default value
|
||||
|
||||
//site/srv/cch info
|
||||
state->nxdn_location_site_code = 0;
|
||||
@@ -1311,22 +1308,16 @@
|
||||
//M17 Storage
|
||||
memset (state->m17_lsf, 0, sizeof(state->m17_lsf));
|
||||
memset (state->m17_pkt, 0, sizeof(state->m17_pkt));
|
||||
state->m17_pbc_ct = 0;
|
||||
state->m17_str_dt = 9;
|
||||
|
||||
//misc str storage
|
||||
// sprintf (state->str50a, "%s", "");
|
||||
memset (state->str50b, 0, 50*sizeof(char));
|
||||
memset (state->str50c, 0, 50*sizeof(char));
|
||||
memset (state->m17sms, 0, 800*sizeof(char));
|
||||
sprintf (state->m17dat, "%s", "");
|
||||
|
||||
state->m17_dst = 0;
|
||||
state->m17_src = 0;
|
||||
state->m17_can = 0; //can value that was decoded from signal
|
||||
state->m17_can_en = -1; //can value supplied to the encoding side
|
||||
state->m17_rate = 48000; //sampling rate for audio input
|
||||
state->m17_vox = 0; //vox mode enabled on M17 encoder
|
||||
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
|
||||
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
|
||||
sprintf (state->m17_dst_str, "%s", "");
|
||||
@@ -1334,10 +1325,19 @@
|
||||
|
||||
state->m17_enc = 0;
|
||||
state->m17_enc_st = 0;
|
||||
state->m17encoder_tx = 0;
|
||||
state->m17encoder_eot = 0;
|
||||
memset(state->m17_meta, 0, sizeof(state->m17_meta));
|
||||
|
||||
memset(state->m17_aes_iv, 0, sizeof(state->m17_aes_iv));
|
||||
|
||||
memset(state->m17_text_string, 0, sizeof(state->m17_text_string));
|
||||
memset(state->m17_gnss_string, 0, sizeof(state->m17_gnss_string));
|
||||
memset(state->m17_data_string, 0, sizeof(state->m17_data_string));
|
||||
memset(state->m17_meta_string, 0, sizeof(state->m17_meta_string));
|
||||
sprintf (state->m17_text_string, "%s", "");
|
||||
sprintf (state->m17_gnss_string, "%s", "");
|
||||
sprintf (state->m17_data_string, "%s", "");
|
||||
sprintf (state->m17_meta_string, "%s", "");
|
||||
|
||||
state->m17_viterbi_err = 0.0f;
|
||||
|
||||
#ifdef USE_CODEC2
|
||||
state->codec2_3200 = codec2_create(CODEC2_MODE_3200);
|
||||
@@ -1395,8 +1395,6 @@
|
||||
printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n");
|
||||
printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n");
|
||||
printf (" tcp:192.168.7.5:7355 for custom address and port \n");
|
||||
printf (" m17udp for M17 UDP/IP socket bind input (default host 127.0.0.1; default port 17000)\n");
|
||||
printf (" m17udp:192.168.7.8:17001 for M17 UDP/IP bind input (Binding Address and Port\n");
|
||||
printf (" filename.bin for OP25/FME capture bin files\n");
|
||||
printf (" filename.wav for 48K/1 wav files (SDR++, GQRX)\n");
|
||||
printf (" filename.wav -s 96000 for 96K/1 wav files (DSDPlus)\n");
|
||||
@@ -1419,8 +1417,6 @@
|
||||
printf (" null for no audio output\n");
|
||||
printf (" udp for UDP socket blaster output (default host 127.0.0.1; default port 23456)\n");
|
||||
printf (" udp:192.168.7.8:23470 for UDP socket blaster output (Target Address and Port\n");
|
||||
printf (" m17udp for M17 UDP/IP socket blaster output (default host 127.0.0.1; default port 17000)\n");
|
||||
printf (" m17udp:192.168.7.8:17001 for M17 UDP/IP blaster output (Target Address and Port\n");
|
||||
printf (" -d <dir> Create mbe data files, use this directory (TDMA version is experimental)\n");
|
||||
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" -g <float> Audio Digital Output Gain (Default: 0 = Auto; )\n");
|
||||
@@ -1467,28 +1463,6 @@
|
||||
printf (" Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T\n");
|
||||
printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2\n");
|
||||
printf ("\n");
|
||||
printf ("Encoder options:\n");
|
||||
printf (" -fZ M17 Stream Voice Encoder\n");
|
||||
printf (" Example: dsd-fme -fZ -M M17:9:DSD-FME:LWVMOBILE -i pulse -6 m17signal.wav -8 -N 2> m17encoderlog.txt\n");
|
||||
printf (" Run M17 Encoding, listening to pulse audio server, with internal decode/playback and output to 48k/1 wav file\n");
|
||||
printf ("\n");
|
||||
printf (" Example: dsd-fme -fZ -M M17:9:DSD-FME:LWVMOBILE -i tcp -o pulse -8 -N 2> m17encoderlog.txt\n");
|
||||
printf (" Run M17 Encoding, listening to default tcp input, without internal decode/playback and output to 48k/1 analog output device\n");
|
||||
printf ("\n");
|
||||
printf (" -fP M17 Packet Encoder\n");
|
||||
printf (" Example: dsd-fme -fP -M M17:9:DSD-FME:LWVMOBILE -6 m17pkt.wav -8 -S 'Hello World'\n");
|
||||
printf ("\n");
|
||||
printf (" -fB M17 BERT Encoder\n");
|
||||
printf (" Example: dsd-fme -fB -M M17:9:DSD-FME:LWVMOBILE -6 m17bert.wav -8\n");
|
||||
printf ("\n");
|
||||
printf (" -M M17 Encoding User Configuration String: M17:CAN:SRC:DST:INPUT_RATE:VOX (see examples above).\n");
|
||||
printf (" CAN 1-15; SRC and DST have to be no more than 9 UPPER base40 characters.\n");
|
||||
printf (" BASE40: ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.'\n");
|
||||
printf (" Input Rate Default is 48000; Use Multiples of 8000 up to 48000.\n");
|
||||
printf (" VOX Enabled on 1; (Default = 0)\n");
|
||||
printf (" Values not entered into the M17: string are set to default values.\n");
|
||||
// printf (" -S M17 Packet Encoder SMS String: No more than 772 chars, use single quotations (see example above).\n");
|
||||
// printf (" -S M17 Stream Encoder SMS String: No more than 48 chars, activates 1600 voice (best if broken into six 8 char chunks).\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Auto Detection\n");
|
||||
printf (" -fA Passive Analog Audio Monitor\n");
|
||||
@@ -1500,7 +1474,6 @@
|
||||
printf (" -fx Decode only X2-TDMA\n");
|
||||
printf (" -fy Decode only YSF\n");
|
||||
printf (" -fz Decode only M17*\n");
|
||||
printf (" -fU Decode only M17 UDP/IP Frame***\n");
|
||||
printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
|
||||
printf (" -fn Decode only NXDN96* (12.5 kHz)\n");
|
||||
printf (" -fp Decode only ProVoice*\n");
|
||||
@@ -1516,15 +1489,15 @@
|
||||
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
||||
printf (" -xr Expect inverted DMR signal\n");
|
||||
printf (" -xd Expect inverted ICOM dPMR signal\n");
|
||||
printf (" -xz Expect inverted M17 signal\n");
|
||||
printf ("\n");
|
||||
printf (" * denotes frame types that cannot be auto-detected.\n");
|
||||
printf (" ** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.\n");
|
||||
printf (" *** configure UDP Input with -i m17:127.0.0.1:17000 \n");
|
||||
printf ("\n");
|
||||
printf ("Advanced Decoder options:\n");
|
||||
printf (" -X <hex> Manually Set P2 Parameters (WACN, SYSID, CC/NAC)\n");
|
||||
printf (" (-X BEE00ABC123)\n");
|
||||
printf (" -_ <dec> Manually Set NXDN PN95 Dibit Scrambler Seed (1-511)\n");
|
||||
printf (" (-* 261)\n");
|
||||
printf (" -D <dec> Manually Set TIII DMR Location Area n bit len (0-10)(10 max)\n");
|
||||
printf (" (Value defaults to max n bit value for site model size)\n");
|
||||
printf (" (Setting 0 will show full Site ID, no area/subarea)\n");
|
||||
@@ -1539,18 +1512,17 @@
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
||||
printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
||||
printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n");
|
||||
printf (" -F Relax M17 LSF/PKT CRC Error Checking\n");
|
||||
printf ("\n");
|
||||
printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
||||
printf (" (NOTE: This used to be the 'K' option! \n");
|
||||
printf (" (NOTE: This used to be the 'K' option!) \n");
|
||||
printf ("\n");
|
||||
printf (" -H <hex> Manually Enter Hytera 10/32/64 Char Basic Privacy Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -H 0B57935150 \n");
|
||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
||||
printf ("\n"); //may move to using the rkey_array with an offset for additional key values
|
||||
printf (" -H <hex> Manually Enter AES-128 or AES-256 Hex Key (see example below)\n");
|
||||
printf ("\n");
|
||||
printf (" -H <hex> Manually Enter AES-128, AES-256, or Kirisun-256 Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
||||
@@ -1561,14 +1533,28 @@
|
||||
printf (" \n");
|
||||
printf (" -2 <hex> Manually Enter and Enforce TYT 16-bit BP Key Value (DMR) (Hex Value) \n");
|
||||
printf (" \n");
|
||||
printf (" -! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) AP Hex Key (see example below)\n");
|
||||
printf (" -! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) 128 or 256 bit AP Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -! '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" -! '1111111111111111 1111111111111111 1111111111111111 1111111111111111' \n");
|
||||
printf (" \n");
|
||||
printf (" -@ <hex> Manually Enter and Enforce Retevis Advanced Privacy (RC2) 128 or 256 bit AP Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -@ '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" -@ '1122334455667788 99AABBCCDDEEFF11 1122334455667788 99AABBCCDDEEFF11' \n");
|
||||
printf (" \n");
|
||||
printf (" -5 <hex> Manually Enter and Enforce TYT Enhanced Privacy (AES-128) EP Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -5 '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" \n");
|
||||
printf (" -+ <hex> Manually Enter and Enforce Baofeng Advanced Privacy (PC5-128 or PC5-256) AP Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -+ 'ABCDABCDABCDABCD ABDCDABCDABCDABC' \n");
|
||||
printf (" -+ 'ABCDABCDABCDABCD ABDCDABCDABCDABC EF01EF01EF01EF01 EF01EF01EF01EF01' \n");
|
||||
printf (" \n");
|
||||
printf (" -^ <hex> Manually Enter and Enforce Connect Systems 72-bit (9-byte) Extended Encryption Hex Key (see example below)\n");
|
||||
printf (" -^ 3BBE782C0430008271\n");
|
||||
printf (" \n");
|
||||
printf (" -9 <dec> Manually Enter and Enforce Kenwood 15-bit Scrambler Key Value (DMR) (Dec Value) \n");
|
||||
printf (" \n");
|
||||
printf (" -A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value) \n");
|
||||
@@ -1580,6 +1566,8 @@
|
||||
printf (" -S 49:123456789ABC80\n");
|
||||
printf (" For Example, enter 49-bit Keystream (MBP 70) as:\n");
|
||||
printf (" -S 49:ED0AED4AED4AED4A\n");
|
||||
printf (" For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:\n");
|
||||
printf (" -S 49:11AA22BB33CC44\n");
|
||||
printf (" \n");
|
||||
printf (" -k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.\n");
|
||||
printf (" Only supports NXDN, DMR Basic Privacy (decimal value). \n");
|
||||
@@ -1592,6 +1580,8 @@
|
||||
printf (" \n");
|
||||
printf (" -0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR) \n");
|
||||
printf (" \n");
|
||||
printf (" -M <hex> Force Entered Alg ID Value over Missing PI header/LE Encryption Identifiers (DMR) \n");
|
||||
printf (" \n");
|
||||
printf (" -3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
|
||||
printf (" Note: Disable this if false positives on Voice ENC occur. \n");
|
||||
printf ("\n");
|
||||
@@ -1819,9 +1809,6 @@
|
||||
if (opts->udp_sockfdA)
|
||||
close (opts->udp_sockfdA);
|
||||
|
||||
if (opts->m17_udp_sock)
|
||||
close (opts->m17_udp_sock);
|
||||
|
||||
//close MBE out files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
@@ -1899,7 +1886,7 @@
|
||||
|
||||
exitflag = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF!:01:2:345:6:7:89:Ek:I:J:O")) != -1)
|
||||
while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:G:D:L:V:U:YK:b:H:X:M:NQ:WrlZTF@:!:01:2:345:6:^:7:8_:9:Ek:I:J:O+:")) != -1)
|
||||
{
|
||||
|
||||
switch (c)
|
||||
@@ -1913,8 +1900,9 @@
|
||||
opts.call_alert = 1;
|
||||
break;
|
||||
|
||||
//Free'd up switches include: j, O,
|
||||
//
|
||||
//Free'd up switches include: j, M,
|
||||
//NOTE: Don't use -*, found it exhibits unusual behavior, was setting
|
||||
//itself to -3 for some reason, may be reading contents of directory
|
||||
|
||||
//make sure to put a colon : after each if they need an argument
|
||||
//or remove colon if no argument required
|
||||
@@ -1934,20 +1922,6 @@
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
//Specify M17 encoder User Data (CAN, DST, SRC values)
|
||||
//NOTE: Disabled QPSK settings by borrowing these switches (nobody probalby used them anyways)
|
||||
case 'M':
|
||||
strncpy(state.m17dat, optarg, 49);
|
||||
state.m17dat[49] = '\0';
|
||||
break;
|
||||
|
||||
// //Specify M17 encoder SMS Message (truncates at 772)
|
||||
// case 'S':
|
||||
// strncpy(state.m17sms, optarg, 772);
|
||||
// state.m17sms[772] = '\0';
|
||||
// state.m17_str_dt = 3; //flip this so that STR encoder knows to use 1600 voice + data
|
||||
// break;
|
||||
|
||||
//specify TG Hold value
|
||||
case 'I':
|
||||
sscanf (optarg, "%d", &state.tg_hold);
|
||||
@@ -1962,9 +1936,14 @@
|
||||
|
||||
//rc4 enforcement on DMR (due to missing the PI header)
|
||||
case '0':
|
||||
state.M = 0x21;
|
||||
state.forced_alg_id = 0x21;
|
||||
fprintf (stderr,"Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)\n");
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
sscanf (optarg, "%hhX", &state.forced_alg_id);
|
||||
fprintf (stderr,"Force DMR ALG ID 0x%02X over Missing PI header/LE Encryption Identifiers (DMR)\n", state.forced_alg_id);
|
||||
break;
|
||||
|
||||
//load single rc4/des key
|
||||
case '1':
|
||||
@@ -1987,12 +1966,24 @@
|
||||
case '!':
|
||||
tyt_ap_pc4_keystream_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//get user Retevis AP Key and Force Its application
|
||||
case '@':
|
||||
retevis_rc2_keystream_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//get user TYT EP Key and Force Its application
|
||||
case '5':
|
||||
tyt_ep_aes_keystream_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//get user CSI EE Key and Force Its application
|
||||
case '^':
|
||||
parse_raw_user_string(optarg, state.static_ks_bits[0]);
|
||||
fprintf (stderr,"DMR CS Extended 72-bit Key with Forced Application\n");
|
||||
state.csi_ee = 1;
|
||||
break;
|
||||
|
||||
//get user Kenwood DMR Scrambler Key and Force Its application
|
||||
case '9':
|
||||
ken_dmr_scrambler_keystream_creation(&state, optarg);
|
||||
@@ -2003,6 +1994,11 @@
|
||||
anytone_bp_keystream_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//get user Baofeng AP Key and Force Its application
|
||||
case '+':
|
||||
baofeng_ap_pc5_keystream_creation(&state, optarg);
|
||||
break;
|
||||
|
||||
//Straight KS Generation
|
||||
case 'S':
|
||||
straight_mod_xor_keystream_creation(&state, optarg);
|
||||
@@ -2205,7 +2201,15 @@
|
||||
if (state.R > 0x7FFF) state.R = 0x7FFF;
|
||||
//disable keyloader in case user tries to use this and it at the same time
|
||||
state.keyloader = 0;
|
||||
fprintf (stderr, "NXDN Scrambler Key set to: %05lld; \n", state.R);
|
||||
break;
|
||||
|
||||
case '_': //was *
|
||||
sscanf (optarg, "%hu", &state.nxdn_pn95_seed);
|
||||
if (state.nxdn_pn95_seed > 0x1FF) state.nxdn_pn95_seed = 0x1FF;
|
||||
else if (state.nxdn_pn95_seed == 0) state.nxdn_pn95_seed = 228;
|
||||
fprintf (stderr, "NXDN PN95 Seed Value set to: %03d; \n", state.nxdn_pn95_seed);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
//new handling for 10/32/64 Char Key
|
||||
@@ -2237,7 +2241,7 @@
|
||||
break;
|
||||
|
||||
case '4':
|
||||
state.M = 1;
|
||||
state.forced_alg_id = 1;
|
||||
fprintf (stderr,"Force Privacy Key over Encryption Identifiers (DMR BP and NXDN Scrambler) \n");
|
||||
break;
|
||||
|
||||
@@ -2974,40 +2978,6 @@
|
||||
//disable RRC filter for now
|
||||
opts.use_cosine_filter = 0;
|
||||
}
|
||||
else if (optarg[0] == 'Z') //Captial Z to Run the M17 STR encoder
|
||||
{
|
||||
opts.m17encoder = 1;
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
//filters disabled by default, use ncurses VBN switches
|
||||
opts.use_lpf = 0;
|
||||
opts.use_hpf = 0;
|
||||
opts.use_pbf = 0;
|
||||
opts.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "M17 Encoder");
|
||||
}
|
||||
else if (optarg[0] == 'B') //Captial B to Run the M17 BRT encoder
|
||||
{
|
||||
opts.m17encoderbrt = 1;
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
sprintf (opts.output_name, "M17 BERT");
|
||||
}
|
||||
else if (optarg[0] == 'P') //Captial P to Run the M17 PKT encoder
|
||||
{
|
||||
opts.m17encoderpkt = 1;
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
sprintf (opts.output_name, "M17 Packet");
|
||||
}
|
||||
else if (optarg[0] == 'U') //Captial U to Run the M17 UDP IPF decoder
|
||||
{
|
||||
opts.m17decoderip = 1;
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
sprintf (opts.output_name, "M17 IP Frame");
|
||||
fprintf (stderr, "Decoding M17 UDP/IP Frames.\n");
|
||||
}
|
||||
break;
|
||||
//don't mess with the modulations unless you really need to
|
||||
case 'm':
|
||||
@@ -3107,11 +3077,6 @@
|
||||
opts.inverted_dpmr = 1;
|
||||
fprintf (stderr, "Expecting inverted ICOM dPMR signals.\n");
|
||||
}
|
||||
else if (optarg[0] == 'z')
|
||||
{
|
||||
opts.inverted_m17 = 1;
|
||||
fprintf (stderr, "Expecting inverted M17 signals.\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
@@ -3139,48 +3104,6 @@
|
||||
openSerial (&opts, &state);
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "m17udp", 6) == 0)) //M17 UDP Socket Input
|
||||
{
|
||||
fprintf (stderr, "M17 UDP IP Frame Input: ");
|
||||
char * curr;
|
||||
|
||||
curr = strtok(opts.audio_in_dev, ":"); //should be 'm17'
|
||||
if (curr != NULL) ; //continue
|
||||
else goto M17ENDIN; //end early with preset values
|
||||
|
||||
curr = strtok(NULL, ":"); //host address
|
||||
if (curr != NULL) strncpy (opts.m17_hostname, curr, 1023);
|
||||
|
||||
curr = strtok(NULL, ":"); //host port
|
||||
if (curr != NULL) opts.m17_portno = atoi (curr);
|
||||
|
||||
M17ENDIN:
|
||||
fprintf (stderr, "%s:", opts.m17_hostname);
|
||||
fprintf (stderr, "%d \n", opts.m17_portno);
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "m17udp", 6) == 0)) //M17 UDP Socket Output
|
||||
{
|
||||
fprintf (stderr, "M17 UDP IP Frame Output: ");
|
||||
char * curr;
|
||||
|
||||
curr = strtok(opts.audio_out_dev, ":"); //should be 'm17'
|
||||
if (curr != NULL) ; //continue
|
||||
else goto M17ENDOUT; //end early with preset values
|
||||
|
||||
curr = strtok(NULL, ":"); //host address
|
||||
if (curr != NULL) strncpy (opts.m17_hostname, curr, 1023);
|
||||
|
||||
curr = strtok(NULL, ":"); //host port
|
||||
if (curr != NULL) opts.m17_portno = atoi (curr);
|
||||
|
||||
M17ENDOUT:
|
||||
fprintf (stderr, "%s:", opts.m17_hostname);
|
||||
fprintf (stderr, "%d \n", opts.m17_portno);
|
||||
opts.m17_use_ip = 1; //tell the encoder to open the socket
|
||||
opts.audio_out_type = 9; //set to null device
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "tcp", 3) == 0)) //tcp socket input from SDR++ and others
|
||||
{
|
||||
fprintf (stderr, "TCP Direct Link: ");
|
||||
@@ -3578,134 +3501,12 @@
|
||||
signal(SIGINT, handler);
|
||||
signal(SIGTERM, handler);
|
||||
|
||||
//read in any user supplied M17 CAN and/or CSD data
|
||||
if((strncmp(state.m17dat, "M17", 3) == 0))
|
||||
{
|
||||
//read in values
|
||||
//string in format of M17:can:src_csd:dst_csd:input_rate
|
||||
|
||||
//check and capatalize any letters in the CSD
|
||||
for (int i = 0; state.m17dat[i]!='\0'; i++)
|
||||
{
|
||||
if(state.m17dat[i] >= 'a' && state.m17dat[i] <= 'z')
|
||||
state.m17dat[i] = state.m17dat[i] -32;
|
||||
}
|
||||
|
||||
fprintf (stderr, "M17 User Data: ");
|
||||
char * curr;
|
||||
|
||||
// if((strncmp(state.m17dat, "M17", 3) == 0))
|
||||
// goto M17END;
|
||||
|
||||
curr = strtok(state.m17dat, ":"); //should be 'M17'
|
||||
if (curr != NULL) ; //continue
|
||||
else goto M17END; //end early with preset values
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 channel access number
|
||||
if (curr != NULL)
|
||||
state.m17_can_en = atoi(curr);
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 src address
|
||||
if (curr != NULL)
|
||||
{
|
||||
strncpy (state.str50c, curr, 9); //only read first 9
|
||||
state.str50c[9] = '\0';
|
||||
}
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 dst address
|
||||
if (curr != NULL)
|
||||
{
|
||||
strncpy (state.str50b, curr, 9); //only read first 9
|
||||
state.str50b[9] = '\0';
|
||||
}
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 input audio rate
|
||||
if (curr != NULL)
|
||||
state.m17_rate = atoi(curr);
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 vox enable
|
||||
if (curr != NULL)
|
||||
state.m17_vox = atoi(curr);
|
||||
|
||||
// curr = strtok(NULL, ":"); //moved to in and out methods
|
||||
// if (curr != NULL)
|
||||
// opts.m17_use_ip = atoi(curr);
|
||||
|
||||
M17END: ; //do nothing
|
||||
|
||||
//check to make sure can value is no greater than 15 (4 bit value)
|
||||
if (state.m17_can_en > 15)
|
||||
state.m17_can_en = 15;
|
||||
|
||||
//if vox is greater than 1, assume user meant 'yes' and set to one
|
||||
if (state.m17_vox > 1)
|
||||
state.m17_vox = 1;
|
||||
|
||||
//debug print m17dat string
|
||||
// fprintf (stderr, " %s;", state.m17dat);
|
||||
|
||||
fprintf (stderr, " M17:%d:%s:%s:%d;", state.m17_can_en, state.str50c, state.str50b, state.m17_rate);
|
||||
if (state.m17_vox == 1) fprintf (stderr, "VOX;");
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
|
||||
playMbeFiles (&opts, &state, argc, argv);
|
||||
}
|
||||
|
||||
else if (opts.m17encoder == 1)
|
||||
{
|
||||
//disable RRC filter for now
|
||||
opts.use_cosine_filter = 0;
|
||||
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
|
||||
//open any inputs, if not alread opened, OSS input and output already handled
|
||||
if (opts.audio_in_type == 0) openPulseInput(&opts);
|
||||
|
||||
#ifdef USE_RTLSDR
|
||||
else if(opts.audio_in_type == 3)
|
||||
{
|
||||
open_rtlsdr_stream(&opts);
|
||||
opts.rtl_started = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
//All input and output now opened and handled correctly, so let's not break things by tweaking
|
||||
encodeM17STR(&opts, &state);
|
||||
}
|
||||
|
||||
else if (opts.m17encoderbrt == 1)
|
||||
{
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
encodeM17BRT(&opts, &state);
|
||||
}
|
||||
|
||||
else if (opts.m17encoderpkt == 1)
|
||||
{
|
||||
//disable RRC filter for now
|
||||
opts.use_cosine_filter = 0;
|
||||
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
encodeM17PKT(&opts, &state);
|
||||
}
|
||||
|
||||
else if (opts.m17decoderip == 1)
|
||||
{
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
processM17IPF(&opts, &state);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
350
src/dsd_mbe.c
350
src/dsd_mbe.c
@@ -18,6 +18,8 @@
|
||||
#include "dsd.h"
|
||||
#include "bp.h"
|
||||
#include "pc4.h"
|
||||
#include "rc2.h"
|
||||
#include "pc5.h"
|
||||
|
||||
//NOTE: This set of functions will be reorganized and simplified (hopefully) or at least
|
||||
//a more logical flow will be established to jive with the new audio handling
|
||||
@@ -173,6 +175,30 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
unsigned long long int k;
|
||||
int x;
|
||||
|
||||
//keystream and silence conditional items
|
||||
uint64_t silence = 0xF801A99F8CE080; //AMBE+2 default silence vector expressed as a 56-bit hex value.
|
||||
char ambe_silence[49];
|
||||
for (i = 0; i < 49; i++)
|
||||
ambe_silence[i] = (silence >> (55-i)) & 1;
|
||||
//zeroed ambe_d can look like 00000000000580(w/ DMRA IV), 000D2C00000000,
|
||||
//or 00000000000000 look at +24 position for 20 bits (fits all these scenarios)
|
||||
char zeroes[49]; memset(zeroes, 0, sizeof(zeroes));
|
||||
size_t zeroes_threshold = 20;
|
||||
|
||||
if (state->forced_alg_id > 1 && state->forced_alg_id != 0x16) //1 and 0x16 is saved for BP stuff, so anything higher than that (Kirisun, requires svc opts set as well)
|
||||
{
|
||||
if (state->currentslot == 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
state->payload_algid = state->forced_alg_id;
|
||||
state->payload_keyid = 0xFF;
|
||||
}
|
||||
if (state->currentslot == 1 && state->dmr_soR & 0x40)
|
||||
{
|
||||
state->payload_algidR = state->forced_alg_id;
|
||||
state->payload_keyidR = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//these conditions should ensure no clashing with the BP/HBP/Scrambler key loading machanisms already coded in
|
||||
if (state->currentslot == 0 && state->payload_algid != 0 && state->payload_algid != 0x80 && state->keyloader == 1)
|
||||
keyring (opts, state);
|
||||
@@ -448,7 +474,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
|
||||
if ( (state->nxdn_cipher_type == 0x01 && state->R != 0) ||
|
||||
(state->M == 1 && state->R > 0) )
|
||||
(state->forced_alg_id == 1 && state->R > 0) )
|
||||
{
|
||||
|
||||
if (state->payload_miN == 0)
|
||||
@@ -556,7 +582,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
//EXPERIMENTAL!!
|
||||
//load basic privacy key number from array by the tg value (if not forced)
|
||||
//currently only Moto BP and Hytera 10 Char BP
|
||||
if (state->M == 0 && state->payload_algid == 0)
|
||||
if (state->forced_alg_id == 0 && state->payload_algid == 0)
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
hash = state->lasttg & 0xFFFFFF;
|
||||
@@ -582,7 +608,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->M == 1) )
|
||||
(state->K > 0 && state->forced_alg_id == 1) )
|
||||
{
|
||||
k = BPK[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
@@ -594,7 +620,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
|
||||
if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
||||
(state->K1 > 0 && state->M == 1) )
|
||||
(state->K1 > 0 && state->forced_alg_id == 1) )
|
||||
{
|
||||
|
||||
int pos = 0;
|
||||
@@ -712,6 +738,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
(state->currentslot == 0 && state->payload_algid == 0x25 && state->aes_key_loaded[0] == 1 ) || //DMR AES256
|
||||
(state->currentslot == 0 && state->payload_algid == 0x89 && state->aes_key_loaded[0] == 1 ) || //P25 AES128
|
||||
(state->currentslot == 0 && state->payload_algid == 0x84 && state->aes_key_loaded[0] == 1 ) || //P25 AES256
|
||||
(state->currentslot == 0 && state->payload_algid == 0x36 && state->aes_key_loaded[0] == 1 ) || //KIRI ADV
|
||||
(state->currentslot == 0 && state->payload_algid == 0x37 && state->aes_key_loaded[0] == 1 ) || //KIRI UNI
|
||||
(state->currentslot == 0 && state->payload_algid == 0x02 && state->R != 0 ) ) //HYT ENHANCED
|
||||
{
|
||||
|
||||
@@ -746,6 +774,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
n = 0;
|
||||
hytera_enhanced_rc4_setup(opts, state, state->R, state->payload_mi);
|
||||
}
|
||||
if (state->payload_algid == 0x36)
|
||||
{
|
||||
n = 0;
|
||||
kirisun_adv_keystream_creation(state);
|
||||
}
|
||||
if (state->payload_algid == 0x37)
|
||||
{
|
||||
n = 0;
|
||||
kirisun_uni_keystream_creation(state);
|
||||
}
|
||||
|
||||
//Load Keystream Octet Bytes directly into keystream array //TODO: Convert to unpack function
|
||||
for (i = 0; i < 9 * 16; i++) //9 rounds at 16 octets
|
||||
@@ -759,18 +797,17 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
//now we do the bit by bit xor depending on the frame and position of the state bit counter
|
||||
//run 6 instead of 7 so we can just do bit 49 outside of loop to keep extra bits overloading the array
|
||||
z = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
//skip keystream if silence or zeroes (some CCR), else apply keystream directly and increment counter
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->bit_counterL += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->bit_counterL += 49;
|
||||
else
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
ambe_d[z++] ^= state->ks_bitstreamL[state->bit_counterL++];
|
||||
for (i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= state->ks_bitstreamL[state->bit_counterL++];
|
||||
}
|
||||
|
||||
//last bit
|
||||
ambe_d[48] ^= state->ks_bitstreamL[state->bit_counterL++];
|
||||
|
||||
//skip the next 7 bits of the array (if not Hytera Enhanced)
|
||||
if(state->payload_algid != 0x02)
|
||||
state->bit_counterL += 7;
|
||||
@@ -808,15 +845,24 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
//that may occur on some systems that preempt VC6 voice for a RC opportuninity (TXI)
|
||||
//this occurs because we are supposed to either have a a 'repeat' frame, or 'silent' frame play
|
||||
//due to the error, but the keystream application makes it random 'pfft pop' sound instead
|
||||
if (state->errs < 3)
|
||||
rc4_voice_decrypt(state->dropL, 9, 7, rckey, cipher, plain);
|
||||
else memcpy (plain, cipher, sizeof(plain));
|
||||
|
||||
state->dropL += 7;
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->dropL += 7;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->dropL += 7;
|
||||
else
|
||||
{
|
||||
if (state->errs < 3)
|
||||
rc4_voice_decrypt(state->dropL, 9, 7, rckey, cipher, plain);
|
||||
else memcpy (plain, cipher, sizeof(plain));
|
||||
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
state->dropL += 7;
|
||||
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -857,49 +903,115 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
//DMR Retevis AP, Either Slot (static single key'd enforced KS)
|
||||
if (state->retevis_ap == 1)
|
||||
{
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
uint8_t frame1_cipher[49];
|
||||
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
|
||||
decrypt_rc2((CryptoContext *)state->rc2_context, frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = frame1_cipher[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//DMR TYT AP, Either Slot (static single key'd enforced KS)
|
||||
if (state->tyt_ap == 1)
|
||||
{
|
||||
|
||||
short frame1_cipher[49];
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
decrypt_frame_49(frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = ctx.bits[i];
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
short frame1_cipher[49];
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
decrypt_frame_49(frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = ctx.bits[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//DMR BAOFENG AP, Either Slot (static single key'd enforced KS)
|
||||
if (state->baofeng_ap == 1)
|
||||
{
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
short frame1_cipher[49];
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
|
||||
decrypt_frame_49_pc5(frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = ctxpc5.bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
//DMR TYT EP, Either Slot (static single key'd enforced KS)
|
||||
if (state->tyt_ep == 1)
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(ctx.bits[i] & 1);
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(ctx.bits[i] & 1);
|
||||
}
|
||||
}
|
||||
|
||||
//DMR Kenwood Scrambler, Either Slot (static single key'd enforced KS) //should probably break this up, but this is a test for now
|
||||
//DMR Kenwood Scrambler, Either Slot (static single key'd enforced KS)
|
||||
if (state->ken_sc == 1)
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%882] & 1); //Yikes!
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%882] & 1); //Yikes!
|
||||
}
|
||||
}
|
||||
|
||||
//DMR Anytone BP, Either Slot (static single key'd enforced KS)
|
||||
if (state->any_bp == 1)
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%16] & 1); //Yikes!
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%16] & 1); //Yikes!
|
||||
}
|
||||
}
|
||||
|
||||
//Generic Straight Static Keystream
|
||||
if (state->straight_ks == 1)
|
||||
{
|
||||
//disable enc identifiers, if present
|
||||
state->dmr_so = 0;
|
||||
state->payload_algid = 0;
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%state->straight_mod] & 1); //Yikes!
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else
|
||||
{
|
||||
//disable enc identifiers, if present
|
||||
state->dmr_so = 0;
|
||||
state->payload_algid = 0;
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%state->straight_mod] & 1); //Yikes!
|
||||
}
|
||||
}
|
||||
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
||||
@@ -932,7 +1044,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
//EXPERIMENTAL!!
|
||||
//load basic privacy key number from array by the tg value (if not forced)
|
||||
//currently only Moto BP and Hytera 10 Char BP
|
||||
if (state->M == 0 && state->payload_algidR == 0)
|
||||
if (state->forced_alg_id == 0 && state->payload_algidR == 0)
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
hash = state->lasttgR & 0xFFFFFF;
|
||||
@@ -958,7 +1070,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
|
||||
if ( (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ||
|
||||
(state->K > 0 && state->M == 1) )
|
||||
(state->K > 0 && state->forced_alg_id == 1) )
|
||||
{
|
||||
k = BPK[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
@@ -970,7 +1082,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
|
||||
if ( (state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ||
|
||||
(state->K1 > 0 && state->M == 1))
|
||||
(state->K1 > 0 && state->forced_alg_id == 1))
|
||||
{
|
||||
|
||||
int pos = 0;
|
||||
@@ -1088,6 +1200,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x25 && state->aes_key_loaded[1] == 1 ) || //DMR AES256
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x89 && state->aes_key_loaded[1] == 1 ) || //P25 AES128
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x84 && state->aes_key_loaded[1] == 1 ) || //P25 AES256
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x36 && state->aes_key_loaded[1] == 1 ) || //KIRI ADV
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x37 && state->aes_key_loaded[1] == 1 ) || //KIRI UNI
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x02 && state->RR != 0 ) ) //HYT ENHANCED
|
||||
{
|
||||
|
||||
@@ -1122,6 +1236,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
n = 0;
|
||||
hytera_enhanced_rc4_setup(opts, state, state->RR, state->payload_miR);
|
||||
}
|
||||
if (state->payload_algidR == 0x36)
|
||||
{
|
||||
n = 0;
|
||||
kirisun_adv_keystream_creation(state);
|
||||
}
|
||||
if (state->payload_algidR == 0x37)
|
||||
{
|
||||
n = 0;
|
||||
kirisun_uni_keystream_creation(state);
|
||||
}
|
||||
|
||||
//Load Keystream Octet Bytes directly into keystream array
|
||||
for (i = 0; i < 9 * 16; i++) //9 rounds at 16 octets //TODO: Convert to unpack function
|
||||
@@ -1135,18 +1259,17 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
//now we do the bit by bit xor depending on the frame and position of the state bit counter
|
||||
//run 6 instead of 7 so we can just do bit 49 outside of loop to keep extra bits overloading the array
|
||||
z = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
//skip keystream if silence or zeroes (some CCR), else apply keystream directly and increment counter
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->bit_counterR += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->bit_counterR += 49;
|
||||
else
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
ambe_d[z++] ^= state->ks_bitstreamR[state->bit_counterR++];
|
||||
for (i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= state->ks_bitstreamR[state->bit_counterR++];
|
||||
}
|
||||
|
||||
//last bit
|
||||
ambe_d[48] ^= state->ks_bitstreamR[state->bit_counterR++];
|
||||
|
||||
//skip the next 7 bits of the array (if not Hytera Enhanced)
|
||||
if(state->payload_algidR != 0x02)
|
||||
state->bit_counterR += 7;
|
||||
@@ -1184,14 +1307,22 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
//that may occur on some systems that preempt VC6 voice for a RC opportuninity (TXI)
|
||||
//this occurs because we are supposed to either have a a 'repeat' frame, or 'silent' frame play
|
||||
//due to the error, but the keystream application makes it random 'pfft pop' sound instead
|
||||
if (state->errsR < 3)
|
||||
rc4_voice_decrypt(state->dropR, 9, 7, rckey, cipher, plain);
|
||||
else memcpy (plain, cipher, sizeof(plain));
|
||||
state->dropR += 7;
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->dropR += 7;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->dropR += 7;
|
||||
else
|
||||
{
|
||||
if (state->errsR < 3)
|
||||
rc4_voice_decrypt(state->dropR, 9, 7, rckey, cipher, plain);
|
||||
else memcpy (plain, cipher, sizeof(plain));
|
||||
state->dropR += 7;
|
||||
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1233,48 +1364,115 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
|
||||
}
|
||||
|
||||
//DMR Retevis AP, Either Slot (static single key'd enforced KS)
|
||||
if (state->retevis_ap == 1)
|
||||
{
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
uint8_t frame1_cipher[49];
|
||||
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
|
||||
decrypt_rc2((CryptoContext *)state->rc2_context, frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = frame1_cipher[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//DMR TYT AP, Either Slot (static single key'd enforced KS)
|
||||
if (state->tyt_ap == 1)
|
||||
{
|
||||
|
||||
short frame1_cipher[49];
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
decrypt_frame_49(frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = ctx.bits[i];
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
short frame1_cipher[49];
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
decrypt_frame_49(frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = ctx.bits[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//DMR BAOFENG AP, Either Slot (static single key'd enforced KS)
|
||||
if (state->baofeng_ap == 1)
|
||||
{
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
short frame1_cipher[49];
|
||||
for (int i = 0; i < 49; i++) frame1_cipher[i] = ambe_d[i];
|
||||
|
||||
decrypt_frame_49_pc5(frame1_cipher);
|
||||
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
for (int i = 0; i < 49; i++) ambe_d[i] = ctxpc5.bits[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//DMR TYT EP, Either Slot (static single key'd enforced KS)
|
||||
if (state->tyt_ep == 1)
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(ctx.bits[i] & 1);
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0) {}
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0) {}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(ctx.bits[i] & 1);
|
||||
}
|
||||
}
|
||||
|
||||
//DMR Kenwood Scrambler, Either Slot (static single key'd enforced KS) //should probably break this up, but this is a test for now
|
||||
if (state->ken_sc == 1)
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%882] & 1); //Yikes!
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%882] & 1); //Yikes!
|
||||
}
|
||||
}
|
||||
|
||||
//DMR Anytone BP, Either Slot (static single key'd enforced KS)
|
||||
if (state->any_bp == 1)
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%16] & 1); //Yikes!
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%16] & 1); //Yikes!
|
||||
}
|
||||
}
|
||||
|
||||
//Generic Straight Static Keystream
|
||||
if (state->straight_ks == 1)
|
||||
{
|
||||
//disable enc identifiers, if present
|
||||
state->dmr_soR = 0;
|
||||
state->payload_algidR = 0;
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%state->straight_mod] & 1); //Yikes!
|
||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else if (memcmp(ambe_d+24, zeroes+24, zeroes_threshold) == 0)
|
||||
state->static_ks_counter[state->currentslot] += 49;
|
||||
else
|
||||
{
|
||||
//disable enc identifiers, if present
|
||||
state->dmr_soR = 0;
|
||||
state->payload_algidR = 0;
|
||||
for (int i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%state->straight_mod] & 1); //Yikes!
|
||||
}
|
||||
}
|
||||
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR,
|
||||
|
||||
129
src/dsd_misc.c
129
src/dsd_misc.c
@@ -591,4 +591,131 @@ long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as
|
||||
rms = (long int)sqrt((p-err) / len);
|
||||
if (rms < 0) rms = 150;
|
||||
return rms;
|
||||
}
|
||||
}
|
||||
|
||||
//same as symbol levels in m17.h (m17-fme version)
|
||||
const int8_t symbol_list[4]={-3, -1, +1, +3};
|
||||
|
||||
/**
|
||||
* @brief Slice payload symbols into soft dibits.
|
||||
* Input (RRC filtered baseband sampled at symbol centers)
|
||||
* should be already normalized to {-3, -1, +1 +3}.
|
||||
* @param out Soft valued dibits (type-4).
|
||||
* @param inp Array of 184 floats (1 sample per symbol).
|
||||
*/
|
||||
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD])
|
||||
{
|
||||
|
||||
for(uint8_t i=0; i<SYM_PER_PLD; i++)
|
||||
{
|
||||
//bit 0
|
||||
if(inp[i]>=symbol_list[3])
|
||||
{
|
||||
out[i*2+1]=0xFFFF;
|
||||
}
|
||||
else if(inp[i]>=symbol_list[2])
|
||||
{
|
||||
out[i*2+1]=-(float)0xFFFF/(symbol_list[3]-symbol_list[2])*symbol_list[2]+inp[i]*(float)0xFFFF/(symbol_list[3]-symbol_list[2]);
|
||||
}
|
||||
else if(inp[i]>=symbol_list[1])
|
||||
{
|
||||
out[i*2+1]=0x0000;
|
||||
}
|
||||
else if(inp[i]>=symbol_list[0])
|
||||
{
|
||||
out[i*2+1]=(float)0xFFFF/(symbol_list[1]-symbol_list[0])*symbol_list[1]-inp[i]*(float)0xFFFF/(symbol_list[1]-symbol_list[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
out[i*2+1]=0xFFFF;
|
||||
}
|
||||
|
||||
//bit 1
|
||||
if(inp[i]>=symbol_list[2])
|
||||
{
|
||||
out[i*2]=0x0000;
|
||||
}
|
||||
else if(inp[i]>=symbol_list[1])
|
||||
{
|
||||
out[i*2]=0x7FFF-inp[i]*(float)0xFFFF/(symbol_list[2]-symbol_list[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
out[i*2]=0xFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Soft logic NOT.
|
||||
*
|
||||
* @param a Input A.
|
||||
* @return uint16_t Output = not A.
|
||||
*/
|
||||
uint16_t soft_bit_NOT(const uint16_t a)
|
||||
{
|
||||
return 0xFFFFU-a;
|
||||
}
|
||||
|
||||
//randomizing pattern
|
||||
const uint8_t rand_seq[46]=
|
||||
{
|
||||
0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8,
|
||||
0x6E, 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Randomize type-4 soft bits.
|
||||
*
|
||||
* @param inp Input 368 soft type-4 bits.
|
||||
*/
|
||||
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2])
|
||||
{
|
||||
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
|
||||
{
|
||||
if((rand_seq[i/8]>>(7-(i%8)))&1) //flip bit if '1'
|
||||
{
|
||||
inp[i]=soft_bit_NOT(inp[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//interleaver pattern
|
||||
const uint16_t intrl_seq[SYM_PER_PLD*2]=
|
||||
{
|
||||
0, 137, 90, 227, 180, 317, 270, 39, 360, 129, 82, 219, 172, 309, 262, 31,
|
||||
352, 121, 74, 211, 164, 301, 254, 23, 344, 113, 66, 203, 156, 293, 246, 15,
|
||||
336, 105, 58, 195, 148, 285, 238, 7, 328, 97, 50, 187, 140, 277, 230, 367,
|
||||
320, 89, 42, 179, 132, 269, 222, 359, 312, 81, 34, 171, 124, 261, 214, 351,
|
||||
304, 73, 26, 163, 116, 253, 206, 343, 296, 65, 18, 155, 108, 245, 198, 335,
|
||||
288, 57, 10, 147, 100, 237, 190, 327, 280, 49, 2, 139, 92, 229, 182, 319,
|
||||
272, 41, 362, 131, 84, 221, 174, 311, 264, 33, 354, 123, 76, 213, 166, 303,
|
||||
256, 25, 346, 115, 68, 205, 158, 295, 248, 17, 338, 107, 60, 197, 150, 287,
|
||||
240, 9, 330, 99, 52, 189, 142, 279, 232, 1, 322, 91, 44, 181, 134, 271,
|
||||
224, 361, 314, 83, 36, 173, 126, 263, 216, 353, 306, 75, 28, 165, 118, 255,
|
||||
208, 345, 298, 67, 20, 157, 110, 247, 200, 337, 290, 59, 12, 149, 102, 239,
|
||||
192, 329, 282, 51, 4, 141, 94, 231, 184, 321, 274, 43, 364, 133, 86, 223,
|
||||
176, 313, 266, 35, 356, 125, 78, 215, 168, 305, 258, 27, 348, 117, 70, 207,
|
||||
160, 297, 250, 19, 340, 109, 62, 199, 152, 289, 242, 11, 332, 101, 54, 191,
|
||||
144, 281, 234, 3, 324, 93, 46, 183, 136, 273, 226, 363, 316, 85, 38, 175,
|
||||
128, 265, 218, 355, 308, 77, 30, 167, 120, 257, 210, 347, 300, 69, 22, 159,
|
||||
112, 249, 202, 339, 292, 61, 14, 151, 104, 241, 194, 331, 284, 53, 6, 143,
|
||||
96, 233, 186, 323, 276, 45, 366, 135, 88, 225, 178, 315, 268, 37, 358, 127,
|
||||
80, 217, 170, 307, 260, 29, 350, 119, 72, 209, 162, 299, 252, 21, 342, 111,
|
||||
64, 201, 154, 291, 244, 13, 334, 103, 56, 193, 146, 283, 236, 5, 326, 95,
|
||||
48, 185, 138, 275, 228, 365, 318, 87, 40, 177, 130, 267, 220, 357, 310, 79,
|
||||
32, 169, 122, 259, 212, 349, 302, 71, 24, 161, 114, 251, 204, 341, 294, 63,
|
||||
16, 153, 106, 243, 196, 333, 286, 55, 8, 145, 98, 235, 188, 325, 278, 47
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reorder (interleave) 368 soft bits.
|
||||
*
|
||||
* @param outp Reordered soft bits.
|
||||
* @param inp Input soft bits.
|
||||
*/
|
||||
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2])
|
||||
{
|
||||
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
|
||||
outp[i]=inp[intrl_seq[i]];
|
||||
}
|
||||
|
||||
@@ -34,10 +34,7 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
|
||||
|
||||
//keyboard shortcuts - codes same as ascii codes
|
||||
if (c == 10) //Return / Enter key, open menu
|
||||
{
|
||||
if (opts->m17encoder == 0) //don't allow menu if using M17 encoder
|
||||
ncursesMenu (opts, state);
|
||||
}
|
||||
ncursesMenu (opts, state);
|
||||
|
||||
//use k and l keys to test tg hold toggles on slots 1 and slots 2
|
||||
if (c == 107) //'k' key, hold tg on slot 1 for trunking purposes, or toggle clear
|
||||
@@ -214,14 +211,14 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
|
||||
|
||||
if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr)
|
||||
{
|
||||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||||
else state->M = 1;
|
||||
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
|
||||
else state->forced_alg_id = 1;
|
||||
}
|
||||
|
||||
if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry
|
||||
{
|
||||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||||
else state->M = 0x21;
|
||||
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
|
||||
else state->forced_alg_id = 0x21;
|
||||
}
|
||||
|
||||
if (c == 105) //'i' key, toggle signal inversion on inverted types
|
||||
@@ -233,7 +230,6 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
|
||||
opts->inverted_dpmr = 1;
|
||||
opts->inverted_x2tdma = 1;
|
||||
opts->inverted_ysf = 1;
|
||||
opts->inverted_m17 = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -241,7 +237,6 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->inverted_x2tdma = 0;
|
||||
opts->inverted_ysf = 0;
|
||||
opts->inverted_m17 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,16 +883,6 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
|
||||
else opts->use_hpf_d = 0;
|
||||
}
|
||||
|
||||
if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX
|
||||
{
|
||||
if (state->m17encoder_tx == 0) state->m17encoder_tx = 1;
|
||||
else state->m17encoder_tx = 0;
|
||||
|
||||
//flag on the EOT marker to send last frame after toggling encoder to zero
|
||||
if (state->m17encoder_tx == 0) state->m17encoder_eot = 1;
|
||||
|
||||
}
|
||||
|
||||
if(opts->frame_provoice == 1 && c == 65) //'A' Key, toggle ESK mask 0xA0
|
||||
{
|
||||
if (state->esk_mask == 0) state->esk_mask = 0xA0;
|
||||
|
||||
@@ -921,11 +921,11 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
//toggle enforcement of basic privacy key over enc bit set on traffic
|
||||
if (option == 4)
|
||||
{
|
||||
if (state->M == 1 || state->M == 0x21)
|
||||
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21)
|
||||
{
|
||||
state->M = 0;
|
||||
state->forced_alg_id = 0;
|
||||
}
|
||||
else state->M = 1;
|
||||
else state->forced_alg_id = 1;
|
||||
}
|
||||
|
||||
if (option == 5)
|
||||
@@ -951,11 +951,11 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
//toggle enforcement of rc4 key over missing pi header/le on DMR
|
||||
// if (option == 6)
|
||||
// {
|
||||
// if (state->M == 1 || state->M == 0x21)
|
||||
// if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21)
|
||||
// {
|
||||
// state->M = 0;
|
||||
// state->forced_alg_id = 0;
|
||||
// }
|
||||
// else state->M = 0x21;
|
||||
// else state->forced_alg_id = 0x21;
|
||||
// }
|
||||
|
||||
//load AES keys
|
||||
@@ -1415,7 +1415,6 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
opts->inverted_dpmr = 1;
|
||||
opts->inverted_x2tdma = 1;
|
||||
opts->inverted_ysf = 1;
|
||||
opts->inverted_m17 = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1423,7 +1422,6 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->inverted_x2tdma = 0;
|
||||
opts->inverted_ysf = 0;
|
||||
opts->inverted_m17 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -223,9 +223,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("| Symbol Float Input: %s \n", opts->audio_in_dev);
|
||||
}
|
||||
|
||||
if (opts->m17decoderip == 1 && opts->udp_sockfd)
|
||||
printw ("| M17 UDP IP Frame Input: %s:%d \n", opts->m17_hostname, opts->m17_portno);
|
||||
|
||||
if (opts->audio_in_type == 8)
|
||||
{
|
||||
printw ("| TCP Signal Input: %s:%d; %d kHz; 1 Ch; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000);
|
||||
@@ -336,25 +333,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->m17encoder == 1)
|
||||
{
|
||||
printw ("| M17 Encoder:");
|
||||
if (state->m17encoder_tx == 1 && state->m17_vox == 0) printw (" Toggle TX (\\) ON ;");
|
||||
if (state->m17encoder_tx == 0 && state->m17_vox == 0) printw (" Toggle TX (\\) OFF;");
|
||||
if (state->m17_vox == 1) printw (" Vox Mode;");
|
||||
printw (" Input Gain (/|*): %02.0f%% ", opts->audio_gainA);
|
||||
|
||||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||||
if (opts->use_hpf == 1) printw ("HP|"); else printw (" |");
|
||||
if (opts->use_pbf == 1) printw ("PB|"); else printw (" |");
|
||||
if (opts->audio_in_type != 3 && state->m17_vox == 1) printw ( " SQL: %04ld : %04d;", opts->rtl_rms, opts->rtl_squelch_level);
|
||||
printw ("\n");
|
||||
|
||||
}
|
||||
|
||||
if (opts->m17_use_ip == 1)
|
||||
printw ("| M17 UDP IP Frame Output: %s:%d \n", opts->m17_hostname, opts->m17_portno);
|
||||
|
||||
if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir);
|
||||
@@ -517,18 +495,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
#endif
|
||||
// if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
|
||||
if (state->M == 1)
|
||||
if (state->forced_alg_id == 1)
|
||||
{
|
||||
if (state->R != 0) printw ("| Forcing Key Priority -- NXDN Sc Key: %05lld \n", state->R);
|
||||
if (state->K != 0) printw ("| Forcing Key Priority -- Moto BP Key: %03lld \n", state->K);
|
||||
if (state->K1 != 0) printw ("| Forcing Key Priority -- Hytera BP Key: %016llX \n", state->K1);
|
||||
if (state->K != 0 && state->K1 != 0) printw ("| Warning! Multiple DMR Key Types Loaded! \n"); //warning may not be required
|
||||
}
|
||||
if (state->M == 0x21)
|
||||
if (state->forced_alg_id == 0x21)
|
||||
{
|
||||
if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R);
|
||||
}
|
||||
if (state->M == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
|
||||
if (state->forced_alg_id == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
|
||||
|
||||
if (opts->scanner_mode == 1)
|
||||
{
|
||||
@@ -561,7 +539,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->mod_c4fm == 1) printw ("[C4FM]");
|
||||
if (opts->mod_gfsk == 1) printw ("[GFSK]");
|
||||
printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol);
|
||||
if (opts->m17encoder == 1) printw ("| Encoding: [%s] \n", opts->output_name);
|
||||
printw ("| Decoding: [%s] ", opts->output_name);
|
||||
if (opts->aggressive_framesync == 0) printw ("CRC/(RAS) ");
|
||||
//debug -- troubleshoot voice tuning after grant on DMR CC, subsequent grant may not tune because tuner isn't available
|
||||
@@ -654,20 +631,22 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("\n");
|
||||
printw ("| ");
|
||||
|
||||
|
||||
//fill in any extra info, like Meta (IV, etc)
|
||||
if (state->m17_enc == 1)
|
||||
{
|
||||
printw (" Scrambler - Type: %d", state->m17_enc_st);
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("Scrambler - Type: %d", state->m17_enc_st);
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
if (state->m17_enc == 2)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("AES-CTR - IV: ");
|
||||
//display packed meta as IV
|
||||
printw ("AES-CTR IV: ");
|
||||
//display AES IV
|
||||
for (i = 0; i < 16; i++)
|
||||
printw ("%02X", state->m17_meta[i]);
|
||||
printw ("%02X", state->m17_aes_iv[i]);
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
if (state->m17_enc == 3)
|
||||
@@ -676,6 +655,30 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
printw ("\n");
|
||||
printw ("| ");
|
||||
|
||||
//decoded elements from stream
|
||||
char shortm17[72];
|
||||
memset(shortm17, 0, sizeof(shortm17));
|
||||
strncpy (shortm17, state->m17_text_string, 70);
|
||||
shortm17[71] = 0;
|
||||
printw ("META TEXT: %s", shortm17);
|
||||
|
||||
printw ("\n");
|
||||
printw ("| ");
|
||||
memset(shortm17, 0, sizeof(shortm17));
|
||||
strncpy (shortm17, state->m17_gnss_string, 70);
|
||||
shortm17[71] = 0;
|
||||
printw ("META GNSS: %s", shortm17);
|
||||
|
||||
printw ("\n");
|
||||
printw ("| ");
|
||||
memset(shortm17, 0, sizeof(shortm17));
|
||||
strncpy (shortm17, state->m17_data_string, 70);
|
||||
shortm17[71] = 0;
|
||||
printw ("MISC DATA: %s", shortm17);
|
||||
|
||||
printw ("\n");
|
||||
|
||||
}
|
||||
|
||||
@@ -1109,6 +1112,26 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw(" Key: %010llX", state->R);
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algid == 0x36)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Advanced ");
|
||||
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algid == 0x37)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Universal ");
|
||||
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algid == 0x35)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Encryption "); //0x35 is a placeholder if gained through late-entry method and alg is not known
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
printw ("\n");
|
||||
|
||||
@@ -1284,6 +1307,26 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw(" Key: %010llX", state->RR);
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algidR == 0x36)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Advanced ");
|
||||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algidR == 0x37)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Universal ");
|
||||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algidR == 0x35)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Encryption "); //0x35 is a placeholder if gained through late-entry method and alg is not known
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
printw ("\n");
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ void error(char *msg) {
|
||||
|
||||
struct sockaddr_in address;
|
||||
struct sockaddr_in addressA;
|
||||
struct sockaddr_in addressM17;
|
||||
|
||||
//
|
||||
// Connect
|
||||
@@ -324,18 +323,6 @@ void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void *
|
||||
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
|
||||
}
|
||||
|
||||
int m17_socket_receiver(dsd_opts * opts, void * data)
|
||||
{
|
||||
size_t err = 0;
|
||||
struct sockaddr_in cliaddr;
|
||||
socklen_t len = sizeof(cliaddr);
|
||||
|
||||
//receive data from socket
|
||||
err = recvfrom(opts->udp_sockfd, data, 1000, 0, (struct sockaddr * ) & address, &len); //was MSG_WAITALL, but that seems to be = 256
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
//Analog UDP port on +2 of normal open socket
|
||||
void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
||||
{
|
||||
@@ -353,20 +340,6 @@ void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void *
|
||||
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
|
||||
}
|
||||
|
||||
int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
||||
{
|
||||
UNUSED(state);
|
||||
unsigned long long int err = 0;
|
||||
|
||||
//See notes in m17.c on line ~3395 regarding usage
|
||||
|
||||
//send audio or data to socket
|
||||
err = sendto(opts->m17_udp_sock, data, nsam, 0, (const struct sockaddr * ) & addressM17, sizeof(struct sockaddr_in));
|
||||
//RETURN Value should be ACKN or NACK, or PING, or PONG
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
UNUSED(state);
|
||||
@@ -447,46 +420,6 @@ int udp_socket_connectA(dsd_opts * opts, dsd_state * state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udp_socket_connectM17(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
UNUSED(state);
|
||||
|
||||
long int err = 0;
|
||||
err = opts->m17_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf (stderr, " UDP Socket Error %ld\n", err);
|
||||
return (err);
|
||||
}
|
||||
|
||||
// Don't think this is needed, but doesn't seem to hurt to keep it here either
|
||||
int broadcastEnable = 1;
|
||||
err = setsockopt(opts->m17_udp_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
|
||||
return (err);
|
||||
}
|
||||
|
||||
memset((char * ) & addressM17, 0, sizeof(addressM17));
|
||||
addressM17.sin_family = AF_INET;
|
||||
err = addressM17.sin_addr.s_addr = inet_addr(opts->m17_hostname);
|
||||
if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs
|
||||
{
|
||||
fprintf (stderr, " UDP inet_addr Error %ld\n", err);
|
||||
return (err);
|
||||
}
|
||||
|
||||
addressM17.sin_port = htons(opts->m17_portno);
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf (stderr, " UDP htons Error %ld\n", err);
|
||||
return (err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void return_to_cc (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
//extra safeguards due to sync issues with NXDN
|
||||
|
||||
@@ -2299,6 +2299,10 @@ void eot_cc(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
fprintf (stderr, "EOT; \n");
|
||||
|
||||
//skip an arbitrary number of dibits so that the CC can cancel the grant after a dotting sequence
|
||||
//prior to returning to the control channel and getting sent in a loopback to the call channel
|
||||
skipDibit(opts, state, 240*8);
|
||||
|
||||
//watchdog event at this point
|
||||
state->lastsynctype = 38;
|
||||
watchdog_event_history(opts, state, 0);
|
||||
|
||||
@@ -25,26 +25,45 @@
|
||||
#include "dsd.h"
|
||||
#include "nxdn_const.h"
|
||||
|
||||
//NOTE: Descrambling was having an issue without a value inside the brackets, but only when
|
||||
//the PARITY table was disabled, was this due to a memory issue or overflow?
|
||||
static const uint8_t scramble_t[182] = { //values are the position values we need to invert in the descramble
|
||||
2, 5, 6, 7, 10, 12, 14, 16, 17, 22, 23, 25, 26, 27, 28, 30, 33, 34, 36, 37, 38, 41, 45, 47,
|
||||
52, 54, 56, 57, 59, 62, 63, 64, 65, 66, 67, 69, 70, 73, 76, 79, 81, 82, 84, 85, 86, 87, 88,
|
||||
89, 92, 95, 96, 98, 100, 103, 104, 107, 108, 116, 117, 121, 122, 125, 127, 131, 132, 134,
|
||||
137, 139, 140, 141, 142, 143, 144, 145, 147, 151, 153, 154, 158, 159, 160, 162, 164, 165,
|
||||
168, 170, 171, 174, 175, 176, 177, 181
|
||||
};
|
||||
|
||||
|
||||
//decoding functions here
|
||||
void nxdn_descramble(uint8_t dibits[], int len)
|
||||
void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len)
|
||||
{
|
||||
for (int i=0; i<len; i++)
|
||||
|
||||
uint16_t lfsr = state->nxdn_pn95_seed; //default value is 228 / 0xE4
|
||||
|
||||
uint16_t bit = 0;
|
||||
uint8_t pN95[182]; memset (pN95, 0, sizeof(pN95));
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (scramble_t[i] >= len)
|
||||
break;
|
||||
dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits
|
||||
//before feedback, take the bit
|
||||
pN95[i] = lfsr & 1;
|
||||
|
||||
//since this is right shift, the taps are 0 and 4, and not 8 and 4 (9,5)
|
||||
bit = ((lfsr >> 4) ^ (lfsr >> 0)) & 1;
|
||||
lfsr >>= 1;
|
||||
lfsr |= (bit << 8);
|
||||
|
||||
}
|
||||
|
||||
//convert the pN sequence to a scramble table
|
||||
uint8_t scramble_table[182]; memset(scramble_table, 0, sizeof(scramble_table));
|
||||
int k = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (pN95[i] == 1)
|
||||
scramble_table[k++] = i;
|
||||
}
|
||||
|
||||
//the entries into the scramble_table are the dibits (symbols) that are inverted
|
||||
for (int i = 0; i < k; i++)
|
||||
{
|
||||
dibits[scramble_table[i]] ^= 0x2;
|
||||
dibits[scramble_table[i]] &= 0x3;
|
||||
}
|
||||
|
||||
//debug, make sure we don't overflow dibits array
|
||||
// fprintf (stderr, " PN95: K: %d; Len: %d; ", k, len);
|
||||
|
||||
}
|
||||
|
||||
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
@@ -104,11 +123,11 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
crc = crc12f (trellis_buf, 84); //80
|
||||
crc = crc12f (trellis_buf, 80);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
check = check | trellis_buf[80+i];
|
||||
}
|
||||
|
||||
//debug
|
||||
@@ -127,11 +146,11 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
//fill m_data bytes with trellis_buf
|
||||
for(int i = 0; i < 12; i++)
|
||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
||||
crc = crc12f (trellis_buf, 84);
|
||||
crc = crc12f (trellis_buf, 80);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+84];
|
||||
check = check | trellis_buf[i+80];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +303,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
|
||||
fprintf (stderr, "PF 1/1");
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
|
||||
@@ -342,7 +361,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
if (part_of_frame == 0)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
|
||||
// if (crc != check)
|
||||
@@ -359,13 +378,13 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
//this seems to work much better now
|
||||
else if (part_of_frame != 0 && state->nxdn_cipher_type == 0x1)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
|
||||
//advance seed by required number of turns depending on the current pf value
|
||||
int start = 0; int end = part_of_frame;
|
||||
@@ -563,12 +582,15 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
int bf_idx = sf_full-sf_size; //index position for buffer to superframe
|
||||
|
||||
if (sf_fb && sf_pof) //single unit message
|
||||
{
|
||||
memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||
memcpy(state->dmr_pdu_sf[0]+0, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
|
||||
}
|
||||
else //multiple unit message
|
||||
memcpy(state->dmr_pdu_sf[0]+sf_idx, trellis_buf+bf_idx, sf_size*sizeof(uint8_t));
|
||||
|
||||
//if force application of scrambler key, then let's reset, regardless of CRC check
|
||||
if (sf_fb && state->M == 1)
|
||||
if (sf_fb && state->forced_alg_id == 1)
|
||||
state->payload_miN = 0;
|
||||
|
||||
//currently using static values so event log will log something, and do wav files, etc
|
||||
@@ -579,8 +601,10 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
state->nxdn_last_ran = 7;
|
||||
state->nxdn_last_tg = 777;
|
||||
state->nxdn_last_rid = 777;
|
||||
sprintf (state->generic_talker_alias[0], "%s", "JPN DCR");
|
||||
sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s; ", "JPN DCR");
|
||||
|
||||
//disabled with CSM going into Alias Value
|
||||
// sprintf (state->generic_talker_alias[0], "%s", "JPN DCR");
|
||||
// sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s; ", "JPN DCR");
|
||||
|
||||
//sf_fb is the head message in a multi part, or the only message in a single part message
|
||||
if (sf_fb)
|
||||
@@ -652,12 +676,18 @@ void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
}
|
||||
else if (sf_fb && sf_pof) //single
|
||||
{
|
||||
memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//PICH or TCH 144 bit (JPN DCR)
|
||||
//SEE: https://web.archive.org/web/20150417175725/http://arib.or.jp/english/html/overview/doc/1-STD-T98v1_4.pdf
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144], uint8_t lich)
|
||||
{
|
||||
uint8_t deperm[144]; //144
|
||||
uint8_t depunc[192]; //192
|
||||
@@ -714,11 +744,11 @@ void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
crc = crc12f (trellis_buf, 84); //80
|
||||
crc = crc12f (trellis_buf, 80);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
check = check | trellis_buf[80+i];
|
||||
}
|
||||
|
||||
//debug
|
||||
@@ -737,11 +767,11 @@ void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
//fill m_data bytes with trellis_buf
|
||||
for(int i = 0; i < 12; i++)
|
||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
||||
crc = crc12f (trellis_buf, 84);
|
||||
crc = crc12f (trellis_buf, 80);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+84];
|
||||
check = check | trellis_buf[i+80];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,33 +784,72 @@ void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
uint16_t source = (uint16_t)ConvertBitIntoBytes(&trellis_buf[24], 16);
|
||||
uint16_t target = (uint16_t)ConvertBitIntoBytes(&trellis_buf[40], 16);
|
||||
|
||||
//may only be relevant on MFID 0x30 "F.R.C." Radios
|
||||
if (opcode == 0x0F)
|
||||
//SB0 with CSM
|
||||
if (lich == 0x08)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "Source: %d; Target: %d; ", source, target);
|
||||
if (gi)
|
||||
fprintf (stderr, "Private; ");
|
||||
else fprintf (stderr, "Group; ");
|
||||
|
||||
fprintf (stderr, "Data Preamble; ");
|
||||
uint8_t countdown = (uint8_t)ConvertBitIntoBytes(&trellis_buf[64], 8);
|
||||
fprintf (stderr, "Countdown: %d; ", countdown);
|
||||
unsigned long long int csm = 0;
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
csm <<= 4;
|
||||
uint8_t bcd = (uint8_t)ConvertBitIntoBytes(&trellis_buf[0+(i*4)], 4);
|
||||
|
||||
// if (bcd < 10)
|
||||
// csm |= bcd;
|
||||
// else csm |= 0;
|
||||
|
||||
csm |= bcd;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "Call Sign Memory: %09llX; ", csm);
|
||||
|
||||
//Assigning this to talker alias, see notes below on decimal value
|
||||
sprintf (state->generic_talker_alias[0], "CSM %09llX", csm);
|
||||
sprintf (state->event_history_s[0].Event_History_Items[0].alias, "CSM %09llX", csm);
|
||||
|
||||
//convert from hex to string to decimal w/ sscanf
|
||||
// char csm_str[32]; memset(csm_str, 0, sizeof(csm_str));
|
||||
// sprintf (csm_str, "%llX", csm);
|
||||
// unsigned long long int csm_dec = 0;
|
||||
// sscanf(csm_str, "%lld", &csm_dec);
|
||||
|
||||
//the issue is that this value will exceed the bit allotment for nxdn src value (needs long long at 36-bit)
|
||||
//even values in range 100000000 - 200000000 are 33-bits minimum
|
||||
// fprintf (stderr, "Call Sign Memory: %09lld; ", csm_dec);
|
||||
}
|
||||
|
||||
//may only be relevant on MFID 0x30 "F.R.C." Radios
|
||||
if (opcode == 0x32)
|
||||
//anything else
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "Source: %d; Target: %d; ", source, target);
|
||||
if (gi)
|
||||
fprintf (stderr, "Private; ");
|
||||
else fprintf (stderr, "Group; ");
|
||||
|
||||
fprintf (stderr, "Precoded Message; ");
|
||||
uint8_t idx = (uint8_t)ConvertBitIntoBytes(&trellis_buf[64], 8);
|
||||
fprintf (stderr, "Index#: %d;", idx);
|
||||
|
||||
//may only be relevant on MFID 0x30 "F.R.C." Radios
|
||||
if (opcode == 0x0F)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "Source: %d; Target: %d; ", source, target);
|
||||
if (gi)
|
||||
fprintf (stderr, "Private; ");
|
||||
else fprintf (stderr, "Group; ");
|
||||
|
||||
fprintf (stderr, "Data Preamble; ");
|
||||
uint8_t countdown = (uint8_t)ConvertBitIntoBytes(&trellis_buf[64], 8);
|
||||
fprintf (stderr, "Countdown: %d; ", countdown);
|
||||
|
||||
}
|
||||
|
||||
//may only be relevant on MFID 0x30 "F.R.C." Radios
|
||||
if (opcode == 0x32)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "Source: %d; Target: %d; ", source, target);
|
||||
if (gi)
|
||||
fprintf (stderr, "Private; ");
|
||||
else fprintf (stderr, "Group; ");
|
||||
|
||||
fprintf (stderr, "Precoded Message; ");
|
||||
uint8_t idx = (uint8_t)ConvertBitIntoBytes(&trellis_buf[64], 8);
|
||||
fprintf (stderr, "Index#: %d;", idx);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -794,14 +863,18 @@ void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "TCH (CRC ERR)");
|
||||
if (lich == 0x08)
|
||||
fprintf (stderr, "PICH (CRC ERR)");
|
||||
else fprintf (stderr, "TCH (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " TCH Payload ");
|
||||
if (lich == 0x08)
|
||||
fprintf (stderr, " PICH Payload ");
|
||||
else fprintf (stderr, " TCH Payload ");
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
@@ -1282,7 +1355,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
for(int i = 0; i < 4; i++)
|
||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
||||
crc = crc7_scch(trellis_buf, 25);
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+25];
|
||||
@@ -1304,7 +1377,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1416,11 +1489,11 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
crc[j] = crc12f (trellis_buf, 84); //84
|
||||
crc[j] = crc12f (trellis_buf, 80);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check[j] = check[j] << 1;
|
||||
check[j] = check[j] | trellis_buf[84+i]; //84
|
||||
check[j] = check[j] | trellis_buf[80+i];
|
||||
|
||||
}
|
||||
|
||||
@@ -1440,11 +1513,11 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
//fill m_data bytes with trellis_buf
|
||||
for(int i = 0; i < 12; i++)
|
||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
||||
crc[j] = crc12f (trellis_buf, 84);
|
||||
crc[j] = crc12f (trellis_buf, 80);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check[j] = check[j] << 1;
|
||||
check[j] = check[j] | trellis_buf[i+84];
|
||||
check[j] = check[j] | trellis_buf[i+80];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1582,6 +1655,11 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
||||
else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA");
|
||||
else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP");
|
||||
else if (MessageType == 0x3F) fprintf(stderr, " ALIAS");
|
||||
//observed from #318 and found in ARIB STD-B54
|
||||
else if (MessageType == 0x21) fprintf(stderr, " VCALL_ARIB_STD_B54");
|
||||
else if (MessageType == 0x28) fprintf(stderr, " TX_REL_ARIB_STD_B54");
|
||||
else if (MessageType == 0x27) fprintf(stderr, " ALIAS_ARIB_STD_B54");
|
||||
//TODO: Add rest of ARIB STD-B54 Message Types (Also, need to add a flag F1 and F2 check here, or earlier and make a seperate one for this)
|
||||
else fprintf(stderr, " Unknown Message Type: %02X;", MessageType);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
|
||||
@@ -97,6 +97,21 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
*/
|
||||
//Debug: Disable DUP messages if they cause random issues with Type-C trunking (i.e. changing SRC ang TGT IDs, hopping in the middle of calls, etc)
|
||||
|
||||
//observed new messages in #318, should also be noted that F1 and F2 are both set on these messages
|
||||
|
||||
//VCALL and TX_REL custom to certain radios, but they have different elements in them
|
||||
case 0x21:
|
||||
case 0x28:
|
||||
NXDN_decode_VCALL_ARIB(opts, state, ElementsContent);
|
||||
break;
|
||||
|
||||
//Shift-JIS Talker Alias
|
||||
case 0x27:
|
||||
NXDN_decode_ALIAS_ARIB(opts, state, ElementsContent);
|
||||
break;
|
||||
|
||||
//end observations from #318
|
||||
|
||||
//VCALL_ASSGN_DUP
|
||||
case 0x05:
|
||||
|
||||
@@ -174,7 +189,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
if (state->M == 0)
|
||||
if (state->forced_alg_id == 0)
|
||||
state->nxdn_cipher_type = 0;
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
|
||||
@@ -192,7 +207,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
if (state->M == 0)
|
||||
if (state->forced_alg_id == 0)
|
||||
state->nxdn_cipher_type = 0;
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
#endif
|
||||
@@ -674,7 +689,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
|
||||
state->payload_miN = state->R; //should be okay to load here, will test
|
||||
}
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -722,7 +737,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
|
||||
state->payload_miN = state->R; //should be okay to load here, will test
|
||||
}
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1745,7 +1760,7 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
//check the rkey array for a scrambler key value
|
||||
//TGT ID and Key ID could clash though if csv or system has both with different keys
|
||||
if (state->rkey_array[id] != 0) state->R = state->rkey_array[id];
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -1764,7 +1779,7 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
//check the rkey array for a scrambler key value
|
||||
//TGT ID and Key ID could clash though if csv or system has both with different keys
|
||||
if (state->rkey_array[id] != 0) state->R = state->rkey_array[id];
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1859,6 +1874,335 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
|
||||
}
|
||||
|
||||
//ARIB STD-B54 Messages
|
||||
|
||||
//ARIB STD-B54 Page 22 - 選択呼出音声通信 and 選択呼出終話 (Selective Call Info and Call End)
|
||||
void NXDN_decode_VCALL_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
{
|
||||
|
||||
//MFID is the only difference, this is added, the rest are shifted 8 bits down
|
||||
uint8_t mfid = 0;
|
||||
uint8_t CCOption = 0;
|
||||
uint8_t CallType = 0;
|
||||
uint8_t VoiceCallOption = 0;
|
||||
uint16_t SourceUnitID = 0;
|
||||
uint16_t DestinationID = 0;
|
||||
uint8_t CipherType = 0;
|
||||
uint8_t KeyID = 0;
|
||||
uint8_t DuplexMode[32] = {0};
|
||||
uint8_t TransmissionMode[32] = {0};
|
||||
|
||||
uint8_t MessageType;
|
||||
/* Get the "Message Type" field */
|
||||
MessageType = (Message[2] & 1) << 5;
|
||||
MessageType |= (Message[3] & 1) << 4;
|
||||
MessageType |= (Message[4] & 1) << 3;
|
||||
MessageType |= (Message[5] & 1) << 2;
|
||||
MessageType |= (Message[6] & 1) << 1;
|
||||
MessageType |= (Message[7] & 1) << 0;
|
||||
|
||||
if (MessageType == 0x21) fprintf (stderr, "%s", KGRN); //VCALL
|
||||
else if (MessageType == 0x28) fprintf (stderr, "%s", KYEL); //TX_REL
|
||||
|
||||
mfid = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
|
||||
|
||||
/* Decode "CC Option" */
|
||||
CCOption = (uint8_t)ConvertBitIntoBytes(&Message[16], 8);
|
||||
state->NxdnElementsContent.CCOption = CCOption;
|
||||
|
||||
/* Decode "Call Type" */
|
||||
CallType = (uint8_t)ConvertBitIntoBytes(&Message[24], 3);
|
||||
state->NxdnElementsContent.CallType = CallType;
|
||||
|
||||
/* Decode "Voice Call Option" */
|
||||
VoiceCallOption = (uint8_t)ConvertBitIntoBytes(&Message[27], 5);
|
||||
state->NxdnElementsContent.VoiceCallOption = VoiceCallOption;
|
||||
|
||||
/* Decode "Source Unit ID" */
|
||||
SourceUnitID = (uint16_t)ConvertBitIntoBytes(&Message[32], 16);
|
||||
state->NxdnElementsContent.SourceUnitID = SourceUnitID;
|
||||
|
||||
/* Decode "Destination ID" */
|
||||
DestinationID = (uint16_t)ConvertBitIntoBytes(&Message[48], 16);
|
||||
state->NxdnElementsContent.DestinationID = DestinationID;
|
||||
|
||||
/* Decode the "Cipher Type" */
|
||||
CipherType = (uint8_t)ConvertBitIntoBytes(&Message[64], 2);
|
||||
state->NxdnElementsContent.CipherType = CipherType;
|
||||
|
||||
/* Decode the "Key ID" */
|
||||
KeyID = (uint8_t)ConvertBitIntoBytes(&Message[66], 6);
|
||||
state->NxdnElementsContent.KeyID = KeyID;
|
||||
|
||||
fprintf (stderr, "\n MFID: %02X; ", mfid);
|
||||
|
||||
/* Print the "CC Option" */
|
||||
if(CCOption & 0x80) fprintf(stderr, "Emergency ");
|
||||
if(CCOption & 0x40) fprintf(stderr, "Visitor ");
|
||||
if(CCOption & 0x20) fprintf(stderr, "Priority Paging ");
|
||||
|
||||
//Call String for Per Call WAV File
|
||||
sprintf (state->call_string[0], "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
if (CCOption & 0x80) strcat (state->call_string[0], " Emergency");
|
||||
if (CipherType) strcat (state->call_string[0], " Enc");
|
||||
|
||||
if((CipherType == 2) || (CipherType == 3))
|
||||
{
|
||||
state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
|
||||
state->NxdnElementsContent.PartOfNextEncryptedFrame = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
|
||||
state->NxdnElementsContent.PartOfNextEncryptedFrame = 1;
|
||||
}
|
||||
|
||||
/* Print the "Call Type" */
|
||||
fprintf (stderr, "%s - ", NXDN_Call_Type_To_Str(CallType));
|
||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
|
||||
/* Print the "Voice Call Option" */
|
||||
if (MessageType == 0x21) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
||||
if (MessageType == 0x21) fprintf(stderr, "%s %s (%02X) - ", DuplexMode, TransmissionMode, VoiceCallOption);
|
||||
else if (MessageType == 0x28) fprintf (stderr, " Transmission Release - "); //TX_REL
|
||||
|
||||
/* Print Source ID and Destination ID (Talk Group or Unit ID) */
|
||||
fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//if using the keyloader, then check for a key value first by the key id,
|
||||
//and then if not available, check by the destination (TG) id value
|
||||
//also, for DES and AES, set the nxdn_key varialbe to the DestID for IV and KS gen
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
//if Scrambler Key (and not running NXDN96 since that has VCALL in the non-voice frames)
|
||||
//NOTE: The scrambler seed carries on the state->R variable so that will reset incorrectly on NXDN96
|
||||
//NOTE: Observed on system with scrambler and AES keys on same TG, disabling loading DES and AES key by DestID
|
||||
if (CipherType == 1 && opts->frame_nxdn48 == 1 && opts->frame_nxdn96 == 0)
|
||||
{
|
||||
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
|
||||
else if (state->rkey_array[DestinationID] != 0) state->R = state->rkey_array[DestinationID];
|
||||
}
|
||||
|
||||
//if DES Key
|
||||
else if (CipherType == 2)
|
||||
{
|
||||
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
|
||||
// else if (state->rkey_array[DestinationID] != 0)
|
||||
// {
|
||||
// state->R = state->rkey_array[DestinationID];
|
||||
// state->nxdn_key = DestinationID;
|
||||
// }
|
||||
}
|
||||
|
||||
//if AES Key
|
||||
else if (CipherType == 3)
|
||||
{
|
||||
uint32_t kidx = 0;
|
||||
if (state->rkey_array[KeyID] != 0) kidx = KeyID;
|
||||
// else if (state->rkey_array[DestinationID] != 0)
|
||||
// {
|
||||
// kidx = DestinationID;
|
||||
// state->nxdn_key = DestinationID;
|
||||
// }
|
||||
|
||||
state->A1[0] = state->rkey_array[kidx+0x000];
|
||||
state->A2[0] = state->rkey_array[kidx+0x101];
|
||||
state->A3[0] = state->rkey_array[kidx+0x201];
|
||||
state->A4[0] = state->rkey_array[kidx+0x301];
|
||||
|
||||
//check to see if there is a value loaded or not
|
||||
if (state->A1[0] == 0 && state->A2[0] == 0 && state->A3[0] == 0 && state->A4[0] == 0)
|
||||
state->aes_key_loaded[0] = 0;
|
||||
else state->aes_key_loaded[0] = 1;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
state->aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
|
||||
state->aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
|
||||
state->aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
|
||||
state->aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
|
||||
}
|
||||
|
||||
state->R = state->A1[0]; //display KS stub
|
||||
}
|
||||
|
||||
} //end state->keyloader == 1
|
||||
|
||||
/* Print the "Cipher Type" */
|
||||
if(CipherType != 0 && MessageType == 0x21)
|
||||
{
|
||||
fprintf (stderr, "\n %s", KYEL);
|
||||
fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType));
|
||||
}
|
||||
|
||||
/* Print the Key ID */
|
||||
if(CipherType != 0 && MessageType == 0x21)
|
||||
{
|
||||
fprintf(stderr, "Key ID %u - ", KeyID & 0xFF);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CipherType == 0x01 && state->R > 0) //scrambler key value
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, "Value: %05lld", state->R);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CipherType == 0x02 && state->R > 0) //DES key value
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, "Value: %016llX", state->R);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CipherType == 0x03 && state->R > 0) //AES key stub
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, "KS: %016llX", state->R);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//only grab if VCALL
|
||||
if(MessageType == 0x21)
|
||||
{
|
||||
//only assign rid if not spare and not reserved (happens on private calls, unsure of its significance)
|
||||
if ( (VoiceCallOption & 0xF) < 4) //ideally, only want 0, 1, 2, 3, or 4 (or 6, 7 on telephone calls)
|
||||
state->nxdn_last_rid = SourceUnitID;
|
||||
state->nxdn_last_tg = DestinationID;
|
||||
state->nxdn_key = KeyID;
|
||||
if (CallType == 0 || CallType == 1) //broadcast and group
|
||||
state->gi[0] = 0;
|
||||
else if (CallType == 4) //private
|
||||
state->gi[0] = 1;
|
||||
else state->gi[0] = -1; //unassigned on any other values
|
||||
state->nxdn_cipher_type = CipherType;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
state->gi[0] = -1;
|
||||
sprintf (state->generic_talker_alias[0], "%s", "");
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
}
|
||||
|
||||
//set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic
|
||||
if (state->nxdn_cipher_type != 0)
|
||||
{
|
||||
state->dmr_encL = 1;
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0 || state->R != 0)
|
||||
{
|
||||
state->dmr_encL = 0;
|
||||
}
|
||||
|
||||
} /* End NXDN_decode_VCALL_ARIB() */
|
||||
|
||||
void NXDN_decode_ALIAS_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
{
|
||||
|
||||
uint8_t mfid = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
|
||||
|
||||
//ARIB STD-B54 (p171-172) describes this as always having 3 segments
|
||||
//but this is also signalled, so perhaps it can be variable
|
||||
uint8_t seg_num = (uint8_t)ConvertBitIntoBytes(&Message[16], 4);
|
||||
uint8_t seg_len = (uint8_t)ConvertBitIntoBytes(&Message[20], 4);
|
||||
|
||||
uint8_t seg_bytes[12]; memset(seg_bytes, 0, sizeof(seg_bytes));
|
||||
|
||||
int seg_byte_num = 6;
|
||||
for (int i = 0; i < seg_byte_num; i++)
|
||||
seg_bytes[i] = (uint8_t)ConvertBitIntoBytes(&Message[(i*8)+24], 8);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n Multi Segment Alias %d/%d; ", seg_num, seg_len);
|
||||
for (int i = 0; i < seg_byte_num; i++)
|
||||
fprintf (stderr, "%02X", seg_bytes[i]);
|
||||
}
|
||||
else fprintf (stderr, " %d/%d; ", seg_num, seg_len);
|
||||
|
||||
//copy to PDU superframe
|
||||
memcpy(state->dmr_pdu_sf[0]+(seg_num-1)*seg_byte_num, seg_bytes, seg_byte_num*sizeof(uint8_t));
|
||||
|
||||
int len = seg_byte_num * seg_len;
|
||||
|
||||
//TODO: Do a CRC32 Check, currently relying on each SACCH frame CRC instead
|
||||
|
||||
//extract CRC32
|
||||
uint32_t crc_ext = (state->dmr_pdu_sf[0][len-4] << 24) | (state->dmr_pdu_sf[0][len-3] << 16) |
|
||||
(state->dmr_pdu_sf[0][len-2] << 8) | state->dmr_pdu_sf[0][len-1];
|
||||
|
||||
//remove CRC32 bytes
|
||||
if (len > 4)
|
||||
len -= 4;
|
||||
|
||||
if (seg_num == seg_len)
|
||||
{
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n Completed Alias Encoded: ");
|
||||
for (int i = 0; i < (seg_len*seg_byte_num); i++)
|
||||
fprintf (stderr, "%02X", state->dmr_pdu_sf[0][i]);
|
||||
}
|
||||
|
||||
//Alias String
|
||||
char alias[500]; memset(alias, 0, sizeof(alias));
|
||||
int ptr = 0; //pointer to position in alias buffer
|
||||
int k = 0; //pointer to position in completed message
|
||||
uint16_t sjis = 0; //SHIFT-JIS character
|
||||
uint8_t utf8 = 0; //UTF-8 Character
|
||||
uint32_t c16 = 0; //Unicode Character returned from sjis_char_to_unicode
|
||||
|
||||
//SHIFT-JIS to UNICODE Conversion
|
||||
setlocale(LC_ALL, ""); //needed when encoded alias contains Japanese (or probably any non-roman charset that isn't default on users terminal)
|
||||
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n MFID: %02X; Encoded Len: %d; CRC: %04X; Alias: ", mfid, len, crc_ext);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
|
||||
c16 = 0;
|
||||
utf8 = state->dmr_pdu_sf[0][k];
|
||||
sjis = (state->dmr_pdu_sf[0][k] << 8) | state->dmr_pdu_sf[0][k+1];
|
||||
|
||||
if (utf8 >= 0x20 && utf8 < 0x7F)
|
||||
{
|
||||
c16 = sjis_char_to_unicode(utf8);
|
||||
fprintf (stderr, "%lc", c16);
|
||||
k++;
|
||||
}
|
||||
else if (sjis != 0)
|
||||
{
|
||||
c16 = sjis_char_to_unicode(sjis);
|
||||
fprintf (stderr, "%lc", c16);
|
||||
k+=2;
|
||||
}
|
||||
else if (utf8 == 0 && sjis == 0)
|
||||
break;
|
||||
|
||||
//Encode Unicode to UTF-8 if not a pass-through ASCII control character or 0
|
||||
if (c16 >= 0x0020)
|
||||
ptr += utf8_encode(c16, alias+ptr);
|
||||
|
||||
}
|
||||
|
||||
//terminate string failsafe
|
||||
alias[ptr++] = 0x00;
|
||||
alias[ptr++] = 0x00;
|
||||
|
||||
sprintf (state->generic_talker_alias[0], "%s", alias);
|
||||
sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s; ", alias);
|
||||
|
||||
//reset PDU superframe afterwards
|
||||
memset(state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||
}
|
||||
|
||||
} /* End NXDN_decode_ALIAS_ARIB() */
|
||||
|
||||
char * NXDN_Call_Type_To_Str(uint8_t CallType)
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
//collect lich bits first, if they are good, then we can collect the rest of them
|
||||
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
|
||||
|
||||
nxdn_descramble (lich_dibits, 8);
|
||||
nxdn_pn95_dibit_scrambler (state, lich_dibits, 8);
|
||||
|
||||
lich = 0;
|
||||
for (int i=0; i<8; i++) lich |= (lich_dibits[i] >> 1) << (7-i);
|
||||
@@ -128,7 +128,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
lich = lich_full >> 1;
|
||||
|
||||
//special cases on DCR where parity is computed over 7 bits, and not 4 bits
|
||||
if (lich == 0x4A || lich == 0x48 || lich == 0x46)
|
||||
if (lich == 0x08 || lich == 0x4A || lich == 0x48 || lich == 0x46)
|
||||
lich_parity_computed = ((lich_full >> 7) + (lich_full >> 6) + (lich_full >> 5) + (lich_full >> 4) + (lich_full >> 3) + (lich_full >> 2) + (lich_full >> 1)) & 1;
|
||||
|
||||
if (lich_parity_received != lich_parity_computed)
|
||||
@@ -223,9 +223,13 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
sacch2 = 1;
|
||||
break;
|
||||
|
||||
//DCR Data or End Frame
|
||||
//DCR SB0, Data or End Frame
|
||||
case 0x08: //SB0 w/ CSM 9 digit BCD found here
|
||||
sacch2 = 1;
|
||||
pich_tch = 1; //observed 2nd PICH is zero fill
|
||||
break;
|
||||
case 0x48:
|
||||
pich_tch = 3;
|
||||
pich_tch = 3; //may be 1, or 2 TCH (observed possibly both)
|
||||
case 0x4A:
|
||||
sacch2 = 1;
|
||||
break;
|
||||
@@ -343,7 +347,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
dbuf[i+8] = getDibit(opts, state);
|
||||
}
|
||||
|
||||
nxdn_descramble (dbuf, 182); //sizeof(dbuf)
|
||||
nxdn_pn95_dibit_scrambler (state, dbuf, 182);
|
||||
|
||||
//seperate our dbuf (dibit_buffer) into individual bit array
|
||||
for (int i = 0; i < 182; i++)
|
||||
@@ -465,7 +469,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (state->rkey_array[limazulu] != 0)
|
||||
state->R = state->rkey_array[limazulu];
|
||||
|
||||
if (state->R != 0 && state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->R != 0 && state->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
|
||||
//add additional time to last_sync_time for LimaZulu to hold on current frequency
|
||||
//a little longer without affecting normal scan time on trunk_hangtime variable
|
||||
@@ -521,7 +525,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (voice && facch == 1) //facch steal 1 -- before voice
|
||||
{
|
||||
//force scrambler here, but with unspecified key (just use what's loaded)
|
||||
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
if (state->forced_alg_id == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
|
||||
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
|
||||
{
|
||||
@@ -561,8 +565,8 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//DCR
|
||||
if (sacch2) nxdn_deperm_sacch2(opts, state, sacch_bits);
|
||||
if (pich_tch & 1) nxdn_deperm_pich_tch(opts, state, facch_bits_a);
|
||||
if (pich_tch & 2) nxdn_deperm_pich_tch(opts, state, facch_bits_b);
|
||||
if (pich_tch & 1) nxdn_deperm_pich_tch(opts, state, facch_bits_a, lich);
|
||||
if (pich_tch & 2) nxdn_deperm_pich_tch(opts, state, facch_bits_b, lich);
|
||||
|
||||
//only run facch in second slot if its not equal to the first one
|
||||
//ideally, this would work better AFTER decoding/FEC
|
||||
@@ -580,7 +584,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
//update last voice sync time
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
//turn on scrambler if forced by user option
|
||||
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
if (state->forced_alg_id == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
//process voice frame
|
||||
nxdn_voice (opts, state, voice, dbuf);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
|
||||
*/
|
||||
|
||||
//return 0 if channel value is 0 or 0xFFFF
|
||||
if (channel == 0) return 0;
|
||||
// if (channel == 0) return 0; //this is a valid use-case on P25 (observed) this has been in code since Feb 2024, how was this issue not discovered before now
|
||||
if (channel == 0xFFFF) return 0;
|
||||
|
||||
//Note: Base Frequency is calculated as (Base Frequency) x (0.000005 MHz) from the IDEN_UP message.
|
||||
|
||||
@@ -310,6 +310,18 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||
{
|
||||
|
||||
//clear stale keys if loaded
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->R = 0;
|
||||
state->A1[0] = 0;
|
||||
state->A2[0] = 0;
|
||||
state->A3[0] = 0;
|
||||
state->A4[0] = 0;
|
||||
state->aes_key_loaded[0] = 0;
|
||||
// state->H = 0; //shim for above (this apply here?)
|
||||
}
|
||||
|
||||
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
|
||||
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
|
||||
if (state->p25_cc_is_tdma == 1)
|
||||
|
||||
@@ -317,6 +317,18 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
if (opts->floating_point == 1)
|
||||
state->aout_gain = opts->audio_gain;
|
||||
|
||||
//clear stale keys if loaded
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->R = 0;
|
||||
state->A1[0] = 0;
|
||||
state->A2[0] = 0;
|
||||
state->A3[0] = 0;
|
||||
state->A4[0] = 0;
|
||||
state->aes_key_loaded[0] = 0;
|
||||
// state->H = 0; //shim for above (this apply here?)
|
||||
}
|
||||
|
||||
}
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
@@ -346,6 +358,18 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
if (opts->floating_point == 1)
|
||||
state->aout_gainR = opts->audio_gain;
|
||||
|
||||
//clear stale keys if loaded
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->RR = 0;
|
||||
state->A1[1] = 0;
|
||||
state->A2[1] = 0;
|
||||
state->A3[1] = 0;
|
||||
state->A4[1] = 0;
|
||||
state->aes_key_loaded[1] = 0;
|
||||
// state->H = 0; //shim for above (this apply here?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Return to CC on MAC_END_PTT if other slot is idle
|
||||
@@ -760,6 +784,18 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
if (opts->floating_point == 1)
|
||||
state->aout_gain = opts->audio_gain; //reset
|
||||
|
||||
//clear stale keys if loaded
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->R = 0;
|
||||
state->A1[0] = 0;
|
||||
state->A2[0] = 0;
|
||||
state->A3[0] = 0;
|
||||
state->A4[0] = 0;
|
||||
state->aes_key_loaded[0] = 0;
|
||||
// state->H = 0; //shim for above (this apply here?)
|
||||
}
|
||||
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
@@ -785,6 +821,19 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
//reset gain
|
||||
if (opts->floating_point == 1)
|
||||
state->aout_gainR = opts->audio_gain;
|
||||
|
||||
//clear stale keys if loaded
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->RR = 0;
|
||||
state->A1[1] = 0;
|
||||
state->A2[1] = 0;
|
||||
state->A3[1] = 0;
|
||||
state->A4[1] = 0;
|
||||
state->aes_key_loaded[1] = 0;
|
||||
// state->H = 0; //shim for above (this apply here?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Return to CC on MAC_END_PTT if other slot is idle
|
||||
|
||||
@@ -1034,7 +1034,7 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
//init with low pass if decoding P25 or EDACS/Provoice
|
||||
if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1)
|
||||
demod_init_ro2(&demod);
|
||||
else if (opts->analog_only == 1 || opts->m17encoder == 1)
|
||||
else if (opts->analog_only == 1)
|
||||
demod_init_analog(&demod);
|
||||
else demod_init(&demod);
|
||||
output_init(&output);
|
||||
|
||||
1217
src/sjis_unicode.c
Normal file
1217
src/sjis_unicode.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user