26 Commits

Author SHA1 Message Date
lwvmobile
abf28593b1 Fix some Cygwin64 Build Script Issues and Instructions; #324
Use sed to replace line in ITPP CmakeLists.txt file to update the cmake_minimum_required to an acceptible version for newer cmake;

Include SIMD Math Libraries libopenblas, liblapack-devel, libfftw3-devel for Cygwin64;

If perceived performance issues arise, may consider removing the Math Libraries above from Cygwin64 install script
2025-12-14 19:51:34 -05:00
lwvmobile
bc4aeff164 Misc Fixes; #324
Fix cyg_portable.sh for newest version of Cygwin64;

Fix p25_frequency process_channel_to_freq to allow a channel value of (0000);

Fix Event Format Nit and add EOT Delay on CC for EDACS/PV;
2025-12-12 21:51:37 -05:00
lwvmobile
632041a44a M17: Add Packet Identifier 0x07 for TLE; 2025-11-16 14:30:52 -05:00
lwvmobile
f1cd83e924 DCR: Add SB0 Lich Code 0x08 and decode CSM as Alias, if present; #323
NXDN: Fix Type-C SCCH CRC Check (Pass 2);

NXDN: Fix CRC12 Issues;
2025-11-10 20:52:35 -05:00
lwvmobile
50bf004427 DMR: Kirisun LFSR Fix; #319 2025-11-10 20:32:05 -05:00
lwvmobile
85a6372c2e M17: Put ECD Back In; #322
Don't decode signature frames as voice;

Check 1600 Arbitrary Data to see if it has text in it before attempting to decode it;
2025-11-08 12:48:25 -05:00
lwvmobile
eb76ea2039 DMR: Add -M option to allow forcing any algid value;
Remove Setting from DMR_LE and place in MBE section instead;

Change state->M to state->forced_alg_id to make it easier to find later;
2025-10-31 09:41:10 -04:00
lwvmobile
14edf325bc Tweak zeroes_threshold AMBE KS application; 2025-10-31 08:24:53 -04:00
lwvmobile
e11ed353b8 Change custom NXDN PN95 -* argument to -_ ; #318
Using -* exhibits unusual behavior and may read contents of directory and set any value based on what is in there;

Don't use for future CLI arguments;

Update Usage;
2025-10-31 08:13:03 -04:00
lwvmobile
f8521fda99 Don't Apply Keystream when Silence or Zero DMR AMBE Frames; #319
This is primarily a fix for those CCR Radios that use the static silence frame and doesn't encrypt it either at the start of, or end of TX;

The Zeroes Fix (000D2C00000000) is for Anytone or TXI who has a load of zeroes starting, or ending a TX, or during the TXI window on certain VC-F frames;
2025-10-31 08:06:39 -04:00
lwvmobile
fa47d0321b Update and Strip Down M17 Features; #322 2025-10-31 05:58:45 -04:00
lwvmobile
095d982b62 Kirisun Advanced and Universal Encryption Support; #319
Above Commit is by Anonymous Submission;

Add Example Usage of -S for Baofeng DM32 Custom / Basic Encryption Mode;
2025-10-30 02:32:30 -04:00
lwvmobile
0060378321 DMR: Connect Systems Extended Encryption Support; #321 2025-10-16 12:28:16 -04:00
lwvmobile
8ea6415424 DMR: Baofeng Advanced (PC5) Encryption Support; #320
Above Commit is by Anonymous Submission;
2025-10-15 17:57:15 -04:00
lwvmobile
eb24239c51 DMR: LFSR Function for Kirisun Encryption Methods; #319
Add LFSR to DMR Alg Refresh;

Full Link Control and SBLE Tweaks Regarding Kirisun Enc;
2025-10-11 21:02:59 -04:00
lwvmobile
ac1c658870 DMR: Initial Support for Kirisun "Advanced" and "Universal" Encryption Identifiers and Link Control; #319 2025-10-10 05:53:36 -04:00
lwvmobile
cf032ab955 NXDN: Add SHIFT-JIS support and UTF-8 Conversion and decode Talker Alias for MT 0x27 ALIAS_ARIB; #318
NXDN: Redo NXDN VCALL_ARIB based on observed values and ARIB STD-B54;

Add UTF16 to UTF8 encoding for DMR Talker Alias when its UTF16;

Encoding Unicode / UTF16 to UTF8 Allows for display into Ncurses Terminal, Event History, etc when its CJK and not normal ISO7/ ASCII or UTF8 encoded as UTF16;

Might be beneficial to convert and run all encoded text through UTF8 encode in the future.
2025-10-08 19:54:35 -04:00
lwvmobile
2d04878506 NXDN: Add Placeholders with Partial Decode or Assembly for MT 0x21, 0x27, and 0x28; #318 2025-10-08 05:43:38 -04:00
lwvmobile
748bb5b191 Rewrite NXDN Dibit PN95 Code and allow custom seed value; #318 2025-10-07 06:13:19 -04:00
lwvmobile
f3b89f1c51 DMR: Initial Support for Vertex Standard Encrypted PDU Header; #316 2025-09-21 14:09:52 -04:00
lwvmobile
b2d388a210 DMR: Initial Support for Vertex Standard Text PDU on Port 5007; #316 2025-09-21 00:29:04 -04:00
lwvmobile
c883e2bf0b DMR: Tytera AP (PC4) Encryption Support Update to Allow 128-bit or 256-bit keys; 2025-09-20 23:49:33 -04:00
lwvmobile
f8ca0a8e08 DMR: Retevis AP (RC2) Encryption Support Update to Allow 128-bit or 256-bit keys; 2025-09-19 22:44:50 -04:00
lwvmobile
99b1fd2fe2 DMR: Tweaks to PDU Decryption;
Allow Manually Loaded Key Value AES on DMR PDU;

Add support for CCR AES-ECB PDU Decryption;
2025-09-18 12:13:54 -04:00
lwvmobile
b0a46a541d P25: Clear Stale Keys when using the Keyloader and a CC Return is initiated via LCW or Logic on END_PTT; 2025-09-11 23:19:16 -04:00
lwvmobile
3aabd85604 DMR: Retevis / Anytone AP (RC2) Encryption Support; 2025-09-11 22:49:22 -04:00
41 changed files with 5083 additions and 4119 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
View 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
View 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
View 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
View 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
View 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;
}
}

View File

@@ -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++;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, &lt, &err);
else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, &lt, &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, &lt, &err);
// else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, &lt, &err);
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, &lt, &err);
if (err != 0)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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]];
}

View File

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

View File

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

View File

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

View File

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

View File

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

3918
src/m17.c

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff