mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
58 Commits
2026
...
rtl_overha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bf60caa6f | ||
|
|
dc055c6585 | ||
|
|
eb02148491 | ||
|
|
6cdcac5db2 | ||
|
|
a2a70bbb15 | ||
|
|
e2a6e351c5 | ||
|
|
4dfe095a7c | ||
|
|
fede9b4e20 | ||
|
|
493800a0f3 | ||
|
|
c0b6f186bd | ||
|
|
8b423a2f42 | ||
|
|
8ec385fdf2 | ||
|
|
da8b9b6116 | ||
|
|
a866d98e75 | ||
|
|
e094f95b03 | ||
|
|
f052271a16 | ||
|
|
09bf040810 | ||
|
|
48b032e47a | ||
|
|
046846337a | ||
|
|
836da1f556 | ||
|
|
dd8620bc39 | ||
|
|
283d000b59 | ||
|
|
5834127ff7 | ||
|
|
2ce089ccf8 | ||
|
|
4e64ef1c11 | ||
|
|
c764cf0eda | ||
|
|
8b4fa81711 | ||
|
|
106aae1814 | ||
|
|
391048a45a | ||
|
|
1b9c3aa659 | ||
|
|
e9b12b8bc6 | ||
|
|
9e9ae95219 | ||
|
|
86d91512bb | ||
|
|
0b00832b1f | ||
|
|
2655fccdea | ||
|
|
ac8f17bf20 | ||
|
|
0cb38d2c25 | ||
|
|
6fc327c3b6 | ||
|
|
00e7c51a21 | ||
|
|
e2402d0328 | ||
|
|
402cef34a9 | ||
|
|
29be104345 | ||
|
|
f3ec024000 | ||
|
|
412a4dc3b1 | ||
|
|
2eedcc125b | ||
|
|
9b399f31da | ||
|
|
2ec3f9a263 | ||
|
|
0decc5934c | ||
|
|
7dd9cd7566 | ||
|
|
30766b34bd | ||
|
|
e700e418be | ||
|
|
c6d3e4cea0 | ||
|
|
62a9372d61 | ||
|
|
cc200ea82c | ||
|
|
03c6b28de3 | ||
|
|
3fe14f3b1d | ||
|
|
3adcf5f449 | ||
|
|
b81e1e6d22 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,4 +9,5 @@ examples
|
||||
*.ans
|
||||
*.patch
|
||||
*.zip
|
||||
result
|
||||
result
|
||||
.cache
|
||||
@@ -52,13 +52,14 @@ git_describe(GIT_TAG)
|
||||
|
||||
find_package(LibSndFile REQUIRED)
|
||||
find_package(MBE REQUIRED)
|
||||
find_package(ITPP REQUIRED)
|
||||
find_package(RTLSDR)
|
||||
find_package(Curses REQUIRED)
|
||||
find_package(PulseAudio REQUIRED)
|
||||
find_package(CODEC2)
|
||||
|
||||
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS})
|
||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES})
|
||||
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS})
|
||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES})
|
||||
|
||||
if(RTLSDR_FOUND)
|
||||
find_package(Threads)
|
||||
|
||||
15
cmake/FindITPP.cmake
Normal file
15
cmake/FindITPP.cmake
Normal file
@@ -0,0 +1,15 @@
|
||||
# - Try to find ITPP
|
||||
# Once done this will define
|
||||
#
|
||||
# ITPP_FOUND - System has ITPP
|
||||
# ITPP_INCLUDE_DIR - The ITPP include directory
|
||||
# ITPP_LIBRARY - The library needed to use ITPP
|
||||
#
|
||||
|
||||
find_path(ITPP_INCLUDE_DIR itpp/itcomm.h)
|
||||
|
||||
set(ITPP_NAMES ${ITPP_NAMES} itpp libitpp libitpp.dll)
|
||||
FIND_LIBRARY(ITPP_LIBRARY NAMES ${ITPP_NAMES})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ITPP DEFAULT_MSG ITPP_LIBRARY ITPP_INCLUDE_DIR)
|
||||
@@ -70,7 +70,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/*.bat dsd-fme-portable/
|
||||
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/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
|
||||
@@ -94,6 +94,7 @@ if [ "$RELEASE" = "y" ]; then
|
||||
|
||||
#compiled items into release dsd-fme folder
|
||||
cp codec2/build/src/cygcodec2* dsd-fme-portable/dsd-fme/
|
||||
cp itpp-4.3.1/build/itpp/cygitpp* dsd-fme-portable/dsd-fme/
|
||||
cp rtl-sdr/build/src/cyg* dsd-fme-portable/dsd-fme/
|
||||
cp mbelib/build/cygmbe* dsd-fme-portable/dsd-fme/
|
||||
|
||||
@@ -127,6 +128,7 @@ 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/
|
||||
@@ -150,6 +152,7 @@ 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/
|
||||
@@ -176,6 +179,7 @@ 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/
|
||||
|
||||
@@ -17,6 +17,11 @@ if [ "$ANSWER" = "y" ]; then
|
||||
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
|
||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
||||
|
||||
printf "Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal\n"
|
||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
|
||||
@@ -19,6 +19,18 @@ if [ "$ANSWER" = "y" ]; then
|
||||
export LD_LIBRARY_PATH
|
||||
echo $LD_LIBRARY_PATH
|
||||
|
||||
#ITPP
|
||||
cd $cdir
|
||||
printf "Installing itpp 4.3.1 from source http://sourceforge.net/projects/itpp/files/latest/download?source=files\n Please wait!\n"
|
||||
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/
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
make install
|
||||
|
||||
#MBELIB
|
||||
cd $cdir
|
||||
printf "Installing mbelib\n Please wait!\n"
|
||||
|
||||
@@ -12,7 +12,13 @@ read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||
if [ "$ANSWER" = "y" ]; then
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncurses-dev libncurses6 libcodec2-dev
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncurses-dev libncurses6 libcodec2-dev
|
||||
chkitpp=$(dpkg -l libitpp-dev 2>/dev/null | awk '/^ii/ {print 1} END {if (NR == 0) print 0}')
|
||||
if [ "$chkitpp" -lt "1" ];then
|
||||
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
|
||||
read -p "Press Enter to exit..." x
|
||||
exit 1
|
||||
fi
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
|
||||
@@ -12,7 +12,13 @@ read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||
if [ "$ANSWER" = "y" ]; then
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncursesw5-dev libcodec2-dev
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
||||
chkitpp=$(dpkg -l libitpp-dev 2>/dev/null | awk '/^ii/ {print 1} END {if (NR == 0) print 0}')
|
||||
if [ "$chkitpp" -lt "1" ];then
|
||||
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
|
||||
read -p "Press Enter to exit..." x
|
||||
exit 1
|
||||
fi
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
|
||||
@@ -43,9 +43,9 @@ Debian/Mint/Ubuntu/Pi
|
||||
```
|
||||
sudo apt update
|
||||
#Ubuntu 22.04 lts / Debian 11 and lower
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libcodec2-dev
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libcodec2-dev
|
||||
#Ubuntu 24.04 lts / Debian 12
|
||||
#sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncurses-dev libncurses6 libcodec2-dev
|
||||
#sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncurses-dev libncurses6 libcodec2-dev
|
||||
```
|
||||
|
||||
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||
@@ -60,6 +60,8 @@ Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/l
|
||||
```
|
||||
sudo pacman -Syu
|
||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
|
||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
```
|
||||
|
||||
## Headless Ubuntu Server/Pi
|
||||
@@ -67,7 +69,24 @@ sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel
|
||||
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
||||
|
||||
```
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
|
||||
```
|
||||
|
||||
### Build and Install ITPP - ONLY IF NOT IN REPO!!
|
||||
|
||||
```
|
||||
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||
tar xjf itpp*
|
||||
#if you can't cd into this folder, double check folder name first
|
||||
cd itpp-4.3.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Build Version: AW 2025-209-g14edf32
|
||||
Build Version: AW 2025-182-g24c1dd9
|
||||
MBElib Version: 1.3.4
|
||||
CODEC2 Support Enabled
|
||||
|
||||
@@ -23,6 +23,8 @@ 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)
|
||||
@@ -35,6 +37,8 @@ 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; )
|
||||
@@ -77,6 +81,26 @@ 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
|
||||
@@ -88,6 +112,7 @@ 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*
|
||||
@@ -103,15 +128,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)
|
||||
@@ -125,9 +150,10 @@ 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.
|
||||
@@ -135,7 +161,7 @@ Advanced Decoder options:
|
||||
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||
|
||||
-H <hex> Manually Enter AES-128, AES-256, or Kirisun-256 Hex Key (see example below)
|
||||
-H <hex> Manually Enter AES-128 or AES-256 Hex Key (see example below)
|
||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||
@@ -146,28 +172,14 @@ 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) 128 or 256 bit AP Hex Key (see example below)
|
||||
-! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) 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)
|
||||
@@ -179,8 +191,6 @@ 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).
|
||||
@@ -193,8 +203,6 @@ 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.
|
||||
|
||||
@@ -220,5 +228,4 @@ 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
|
||||
@@ -7,6 +7,8 @@
|
||||
*
|
||||
* Code adapted from http://www.aqdi.com/golay.htm
|
||||
*
|
||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
/**
|
||||
* Code taken and adapted from www.eccpage.com/rs.c
|
||||
* Credit goes to Mr Simon Rockliff.
|
||||
*
|
||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
||||
*/
|
||||
|
||||
/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in
|
||||
|
||||
100
include/dsd.h
100
include/dsd.h
@@ -59,9 +59,8 @@
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
//OSS support
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/pulseaudio.h> //PULSE AUDIO
|
||||
#include <pulse/simple.h> //PULSE AUDIO
|
||||
#include <pulse/error.h> //PULSE AUDIO
|
||||
@@ -358,6 +357,10 @@ 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;
|
||||
@@ -368,7 +371,7 @@ typedef struct
|
||||
int rtl_udp_port;
|
||||
int rtl_bandwidth;
|
||||
int rtl_started;
|
||||
long int rtl_rms;
|
||||
long int rtl_pwr;
|
||||
int monitor_input_audio;
|
||||
int analog_only;
|
||||
int pulse_raw_rate_in;
|
||||
@@ -411,6 +414,7 @@ typedef struct
|
||||
short int aggressive_framesync;
|
||||
|
||||
int frame_m17;
|
||||
int inverted_m17;
|
||||
|
||||
FILE *symbolfile;
|
||||
int call_alert;
|
||||
@@ -427,6 +431,12 @@ 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;
|
||||
@@ -633,7 +643,7 @@ typedef struct
|
||||
unsigned long long int K2;
|
||||
unsigned long long int K3;
|
||||
unsigned long long int K4;
|
||||
uint8_t forced_alg_id;
|
||||
int M;
|
||||
int menuopen;
|
||||
|
||||
//AES Key Segments
|
||||
@@ -888,7 +898,6 @@ 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];
|
||||
@@ -943,11 +952,15 @@ 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 PWR value
|
||||
|
||||
char m17_dst_csd[20];
|
||||
char m17_src_csd[20];
|
||||
@@ -955,22 +968,18 @@ typedef struct
|
||||
char m17_src_str[50];
|
||||
char m17_dst_str[50];
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
//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
|
||||
@@ -982,9 +991,6 @@ 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;
|
||||
@@ -992,12 +998,6 @@ 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,6 +1014,13 @@ 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"
|
||||
@@ -1237,6 +1244,13 @@ 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)
|
||||
@@ -1264,7 +1278,7 @@ void ncursesClose ();
|
||||
|
||||
//new NXDN Functions start here!
|
||||
void nxdn_frame (dsd_opts * opts, dsd_state * state);
|
||||
void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len);
|
||||
void nxdn_descramble (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]);
|
||||
@@ -1275,7 +1289,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], uint8_t lich);
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
|
||||
//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]);
|
||||
@@ -1298,12 +1312,6 @@ 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);
|
||||
@@ -1329,10 +1337,6 @@ 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);
|
||||
|
||||
@@ -1576,6 +1580,7 @@ void init_rrc_filter_memory();
|
||||
|
||||
//misc audio filtering for analog
|
||||
long int raw_rms(short *samples, int len, int step);
|
||||
long int raw_pwr(short *samples, int len, int step);
|
||||
void init_audio_filters(dsd_state * state);
|
||||
void lpf(dsd_state * state, short * input, int len);
|
||||
void hpf(dsd_state * state, short * input, int len);
|
||||
@@ -1605,6 +1610,9 @@ 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[]);
|
||||
@@ -1622,29 +1630,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 / Retevis / Anytone / Kenwood / Misc DMR Encryption Modes
|
||||
//Tytera 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);
|
||||
void retevis_rc2_keystream_creation(dsd_state *state, char *input);
|
||||
|
||||
//Misc Other Encryption Modes
|
||||
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);
|
||||
void hytera_enhanced_alg_refresh(dsd_state * state);
|
||||
|
||||
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES
|
||||
void lfsr_64_to_128(uint8_t * iv);
|
||||
void LFSR128(dsd_state * state);
|
||||
void LFSR128n(dsd_state * state);
|
||||
void LFSR128d(dsd_state * state);
|
||||
@@ -1660,7 +1661,7 @@ void cleanup_rtlsdr_stream();
|
||||
int get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
|
||||
void rtlsdr_sighandler();
|
||||
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
||||
long int rtl_return_rms();
|
||||
long int rtl_return_pwr();
|
||||
void rtl_clean_queue();
|
||||
#endif
|
||||
|
||||
@@ -1671,9 +1672,6 @@ int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
|
||||
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
|
||||
int isch_lookup (uint64_t isch); //isch map lookup
|
||||
|
||||
//Phase 1 NID Check
|
||||
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
26
include/p25p1_check_nid.h
Normal file
26
include/p25p1_check_nid.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#ifndef P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
#define P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID.
|
||||
* \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. This includes the
|
||||
* NAC (12 bits), DUID (4 bits) and 47 bits of BCH parity.
|
||||
* \param new_nac Output. An address where to store the calculated NAC value after error correction. Should
|
||||
* be large enough to accommodate for an integer.
|
||||
* \param new_duid Output. An address where to store the calculated DUID value after error correction. Should
|
||||
* be able to accommodate 3 chars.
|
||||
* \param parity Input. The parity value read.
|
||||
* \return 0 if there were errors processing the NID.
|
||||
*/
|
||||
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
147
include/pc5.h
147
include/pc5.h
@@ -1,147 +0,0 @@
|
||||
#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
|
||||
@@ -1,43 +0,0 @@
|
||||
#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
|
||||
@@ -6,6 +6,7 @@
|
||||
, ncurses
|
||||
, pulseaudio
|
||||
, rtl-sdr
|
||||
, itpp
|
||||
, codec2
|
||||
, portaudioSupport ? true
|
||||
, portaudio ? null
|
||||
@@ -22,6 +23,7 @@ stdenv.mkDerivation {
|
||||
buildInputs = [
|
||||
mbelib
|
||||
libsndfile
|
||||
itpp
|
||||
rtl-sdr
|
||||
ncurses.dev
|
||||
pulseaudio.dev
|
||||
@@ -37,7 +39,7 @@ stdenv.mkDerivation {
|
||||
tap audio and synthesize the decoded speech. Speech synthesis requires
|
||||
mbelib, which is a separate package.
|
||||
'';
|
||||
homepage = "https://github.com/lwvmobile/dsd-fme";
|
||||
homepage = "https://github.com/szechyjs/dsd";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
|
||||
417
src/crypt-kir.c
417
src/crypt-kir.c
@@ -1,417 +0,0 @@
|
||||
#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
468
src/crypt-pc5.c
@@ -1,468 +0,0 @@
|
||||
#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
404
src/crypt-rc2.c
@@ -1,404 +0,0 @@
|
||||
#include "rc2.h"
|
||||
#include "dsd.h"
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int n) {
|
||||
return ((x << n) | (x >> (63 - n) >> 1)) & 0xffffffffffffffff;
|
||||
}
|
||||
|
||||
void swapbit(uint64_t* internalstate, uint8_t bit) {
|
||||
unsigned char bitB = bit & 1;
|
||||
if (bitB)
|
||||
*internalstate |= bitB;
|
||||
else
|
||||
*internalstate &= (~bitB ^ 1);
|
||||
}
|
||||
|
||||
// MD2 functions
|
||||
void md2_init(MD2State* state) {
|
||||
state->x1 = 0;
|
||||
state->x2 = 0;
|
||||
memset(state->h2, 0, n1);
|
||||
memset(state->h1, 0, n1 * 3);
|
||||
}
|
||||
|
||||
void md2_hashing(MD2State* state, unsigned char t1[], size_t b6) {
|
||||
static unsigned char s4[256] = {
|
||||
13,199,11,67,237,193,164,77,115,184,141,222,73,
|
||||
38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||
119,22,207,35,198,37,171,167,80,30,219,28,213,
|
||||
121,86,29,214,242,6,4,89,162,110,175,19,157,
|
||||
3,88,234,94,144,118,159,239,100,17,182,173,238,
|
||||
68,16,79,132,54,163,52,9,58,57,55,229,192,
|
||||
170,226,56,231,187,158,70,224,233,245,26,47,32,
|
||||
44,247,8,251,20,197,185,109,153,204,218,93,178,
|
||||
212,137,84,174,24,120,130,149,72,180,181,208,255,
|
||||
189,152,18,143,176,60,249,27,227,128,139,243,253,
|
||||
59,123,172,108,211,96,138,10,215,42,225,40,81,
|
||||
65,90,25,98,126,154,64,124,116,122,5,1,168,
|
||||
83,190,131,191,244,240,235,177,155,228,125,66,43,
|
||||
201,248,220,129,188,230,62,75,71,78,34,31,216,
|
||||
254,136,91,114,106,46,217,196,92,151,209,133,51,
|
||||
236,33,252,127,179,69,7,183,105,146,97,39,15,
|
||||
205,112,200,166,223,45,48,246,186,41,148,140,107,
|
||||
76,85,95,194,142,50,49,134,23,135,169,221,210,
|
||||
203,63,165,82,161,202,53,14,206,232,103,102,195,
|
||||
117,250,99,0,74,160,241,2,113
|
||||
};
|
||||
|
||||
int b4 = 0;
|
||||
|
||||
while (b6) {
|
||||
for (; b6 && state->x2 < n1; b6--, state->x2++) {
|
||||
int b5 = t1[b4++];
|
||||
state->h1[state->x2 + n1] = b5;
|
||||
state->h1[state->x2 + (n1 * 2)] = b5 ^ state->h1[state->x2];
|
||||
state->x1 = state->h2[state->x2] ^= s4[b5 ^ state->x1];
|
||||
}
|
||||
|
||||
if (state->x2 == n1) {
|
||||
int b2 = 0;
|
||||
state->x2 = 0;
|
||||
|
||||
for (int b3 = 0; b3 < (n1 + 2); b3++) {
|
||||
for (int b1 = 0; b1 < (n1 * 3); b1++)
|
||||
b2 = state->h1[b1] ^= s4[b2];
|
||||
b2 = (b2 + b3) % 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void md2_end(MD2State* state, unsigned char h4[n1]) {
|
||||
unsigned char h3[n1];
|
||||
int n4 = n1 - state->x2;
|
||||
for (int i = 0; i < n4; i++) h3[i] = n4;
|
||||
md2_hashing(state, h3, n4);
|
||||
md2_hashing(state, state->h2, sizeof(state->h2));
|
||||
for (int i = 0; i < n1; i++) h4[i] = state->h1[i];
|
||||
}
|
||||
|
||||
// RC4 functions
|
||||
uint64_t next(RC4State* state) {
|
||||
uint64_t z = (state->x += 0x9e3779b97f4a7c15);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
void rc4_init(RC4State* state, unsigned char key[]) {
|
||||
int tmp;
|
||||
|
||||
for (state->i_rc4 = 0; state->i_rc4 < 256; state->i_rc4++) {
|
||||
state->array_rc4[state->i_rc4] = state->i_rc4;
|
||||
}
|
||||
|
||||
state->j_rc4 = 0;
|
||||
for (state->i_rc4 = 0; state->i_rc4 < 256; state->i_rc4++) {
|
||||
state->j_rc4 = (state->j_rc4 + state->array_rc4[state->i_rc4] + key[state->i_rc4 % 256]) % 256;
|
||||
tmp = state->array_rc4[state->i_rc4];
|
||||
state->array_rc4[state->i_rc4] = state->array_rc4[state->j_rc4];
|
||||
state->array_rc4[state->j_rc4] = tmp;
|
||||
}
|
||||
state->i_rc4 = 0;
|
||||
state->j_rc4 = 0;
|
||||
}
|
||||
|
||||
unsigned char rc4_output(RC4State* state) {
|
||||
uint8_t rndbyte, decal;
|
||||
int tmp, t;
|
||||
|
||||
state->i_rc4 = (state->i_rc4 + 1) % 256;
|
||||
state->j_rc4 = (state->j_rc4 + state->array_rc4[state->i_rc4]) % 256;
|
||||
tmp = state->array_rc4[state->i_rc4];
|
||||
state->array_rc4[state->i_rc4] = state->array_rc4[state->j_rc4];
|
||||
state->array_rc4[state->j_rc4] = tmp;
|
||||
t = (state->array_rc4[state->i_rc4] + state->array_rc4[state->j_rc4]) % 256;
|
||||
|
||||
|
||||
if (state->xyz == 0) state->bb = next(state);
|
||||
decal = 56 - (8 * state->xyz);
|
||||
rndbyte = (state->bb >> decal) & 0xff;
|
||||
state->xyz++;
|
||||
if (state->xyz == 8) state->xyz = 0;
|
||||
|
||||
if (state->count == 0) {
|
||||
rndbyte = rndbyte ^ state->array_rc4[t];
|
||||
state->count = 1;
|
||||
} else {
|
||||
rndbyte = rndbyte + state->array_rc4[t];
|
||||
state->count = 0;
|
||||
}
|
||||
|
||||
|
||||
return rndbyte;
|
||||
}
|
||||
|
||||
/* Convert 64-bit integer to bytes (big-endian) */
|
||||
static void u64_to_bytes_be(uint64_t val, unsigned char *out) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out[i] = (unsigned char)((val >> (56 - 8 * i)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
// RC2 functions
|
||||
void rc2_keyschedule(RC2State* state) {
|
||||
unsigned i;
|
||||
// Phase 3 - copy to xkey in little-endian order
|
||||
i = 63;
|
||||
do {
|
||||
state->xkey[i] = ((unsigned char *)state->xkey)[2 * i] +
|
||||
(((unsigned char *)state->xkey)[2 * i + 1] << 8);
|
||||
} while (i--);
|
||||
}
|
||||
|
||||
void rc2_encrypt(RC2State* state) {
|
||||
uint16_t x76, x54, x32, x10, i;
|
||||
|
||||
x76 = (state->plain[7] << 8) + state->plain[6];
|
||||
x54 = (state->plain[5] << 8) + state->plain[4];
|
||||
x32 = (state->plain[3] << 8) + state->plain[2];
|
||||
x10 = (state->plain[1] << 8) + state->plain[0];
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
x10 += (x32 & ~x76) + (x54 & x76) + state->xkey[4 * i + 0];
|
||||
x10 = (x10 << 1) + (x10 >> 15 & 1);
|
||||
|
||||
x32 += (x54 & ~x10) + (x76 & x10) + state->xkey[4 * i + 1];
|
||||
x32 = (x32 << 2) + (x32 >> 14 & 3);
|
||||
|
||||
x54 += (x76 & ~x32) + (x10 & x32) + state->xkey[4 * i + 2];
|
||||
x54 = (x54 << 3) + (x54 >> 13 & 7);
|
||||
|
||||
x76 += (x10 & ~x54) + (x32 & x54) + state->xkey[4 * i + 3];
|
||||
x76 = (x76 << 5) + (x76 >> 11 & 31);
|
||||
|
||||
if (i == 4 || i == 10) {
|
||||
x10 += state->xkey[x76 & 63];
|
||||
x32 += state->xkey[x10 & 63];
|
||||
x54 += state->xkey[x32 & 63];
|
||||
x76 += state->xkey[x54 & 63];
|
||||
}
|
||||
}
|
||||
|
||||
state->cipher[0] = (unsigned char)x10;
|
||||
state->cipher[1] = (unsigned char)(x10 >> 8);
|
||||
state->cipher[2] = (unsigned char)x32;
|
||||
state->cipher[3] = (unsigned char)(x32 >> 8);
|
||||
state->cipher[4] = (unsigned char)x54;
|
||||
state->cipher[5] = (unsigned char)(x54 >> 8);
|
||||
state->cipher[6] = (unsigned char)x76;
|
||||
state->cipher[7] = (unsigned char)(x76 >> 8);
|
||||
|
||||
}
|
||||
|
||||
// Main cryptographic functions
|
||||
void create_keys_rc2(CryptoContext* ctx, unsigned char key1[], size_t size1) {
|
||||
unsigned char h4[n1];
|
||||
|
||||
// Initialize MD2 and hash the key
|
||||
md2_init(&ctx->md2);
|
||||
md2_hashing(&ctx->md2, key1, size1);
|
||||
md2_end(&ctx->md2, h4);
|
||||
|
||||
// Copy first 16 bytes to keys
|
||||
for (int i = 0; i < 16; i++) ctx->keys[i] = h4[i];
|
||||
|
||||
// Initialize RC4 with hashed key
|
||||
rc4_init(&ctx->rc4, h4);
|
||||
|
||||
// Initialize RC4 state variables
|
||||
ctx->rc4.x = 0;
|
||||
for (int i = 0; i < 8; i++) ctx->rc4.x = (ctx->rc4.x << 8) + (h4[256 + i] & 0xff);
|
||||
|
||||
ctx->rc4.xyz = 0;
|
||||
ctx->rc4.count = 0;
|
||||
|
||||
// Warm-up RC4
|
||||
for (int i = 0; i < 22000; i++) rc4_output(&ctx->rc4);
|
||||
|
||||
// Generate RC2 keys
|
||||
int k = rc4_output(&ctx->rc4) + 256;
|
||||
for (int i = 0; i < k; i++) rc4_output(&ctx->rc4);
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
ctx->rc2.xkey[i] = (rc4_output(&ctx->rc4) << 8) + rc4_output(&ctx->rc4);
|
||||
}
|
||||
|
||||
// Generate internal zero value
|
||||
k = rc4_output(&ctx->rc4) + 256;
|
||||
for (int i = 0; i < k; i++) rc4_output(&ctx->rc4);
|
||||
|
||||
ctx->internal_zero = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->internal_zero = (ctx->internal_zero << 8) + rc4_output(&ctx->rc4);
|
||||
}
|
||||
|
||||
// Generate RC2 key schedule
|
||||
rc2_keyschedule(&ctx->rc2);
|
||||
}
|
||||
|
||||
void encryption_rc2(CryptoContext* ctx, uint8_t bits[49]) {
|
||||
ctx->internal_state = ctx->internal_zero;
|
||||
|
||||
for (int sso = 0; sso < 49; sso++) {
|
||||
// Prepare plaintext from internal state
|
||||
ctx->rc2.plain[0] = (ctx->internal_state >> 56) & 0xff;
|
||||
ctx->rc2.plain[1] = (ctx->internal_state >> 48) & 0xff;
|
||||
ctx->rc2.plain[2] = (ctx->internal_state >> 40) & 0xff;
|
||||
ctx->rc2.plain[3] = (ctx->internal_state >> 32) & 0xff;
|
||||
ctx->rc2.plain[4] = (ctx->internal_state >> 24) & 0xff;
|
||||
ctx->rc2.plain[5] = (ctx->internal_state >> 16) & 0xff;
|
||||
ctx->rc2.plain[6] = (ctx->internal_state >> 8) & 0xff;
|
||||
ctx->rc2.plain[7] = ctx->internal_state & 0xff;
|
||||
|
||||
// Encrypt with RC2
|
||||
rc2_encrypt(&ctx->rc2);
|
||||
|
||||
// Reconstruct internal state from ciphertext
|
||||
ctx->internal_state = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->internal_state = (ctx->internal_state << 8) + (ctx->rc2.cipher[i] & 0xff);
|
||||
}
|
||||
|
||||
// XOR the bit and update internal state
|
||||
bits[48 - sso] = bits[48 - sso] ^ (ctx->internal_state & 1);
|
||||
ctx->internal_state = rol64(ctx->internal_state, 1);
|
||||
swapbit(&ctx->internal_state, bits[48 - sso]);
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt_rc2(CryptoContext* ctx, uint8_t bits[49]) {
|
||||
uint8_t tempy;
|
||||
ctx->internal_state = ctx->internal_zero;
|
||||
|
||||
|
||||
for (int sso = 0; sso < 49; sso++) {
|
||||
// Prepare plaintext from internal state
|
||||
ctx->rc2.plain[0] = (ctx->internal_state >> 56) & 0xff;
|
||||
ctx->rc2.plain[1] = (ctx->internal_state >> 48) & 0xff;
|
||||
ctx->rc2.plain[2] = (ctx->internal_state >> 40) & 0xff;
|
||||
ctx->rc2.plain[3] = (ctx->internal_state >> 32) & 0xff;
|
||||
ctx->rc2.plain[4] = (ctx->internal_state >> 24) & 0xff;
|
||||
ctx->rc2.plain[5] = (ctx->internal_state >> 16) & 0xff;
|
||||
ctx->rc2.plain[6] = (ctx->internal_state >> 8) & 0xff;
|
||||
ctx->rc2.plain[7] = ctx->internal_state & 0xff;
|
||||
|
||||
// Encrypt with RC2
|
||||
rc2_encrypt(&ctx->rc2);
|
||||
|
||||
// Reconstruct internal state from ciphertext
|
||||
ctx->internal_state = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->internal_state = (ctx->internal_state << 8) + (ctx->rc2.cipher[i] & 0xff);
|
||||
}
|
||||
|
||||
// XOR the bit and update internal state
|
||||
tempy = bits[48 - sso];
|
||||
bits[48 - sso] = bits[48 - sso] ^ (ctx->internal_state & 1);
|
||||
ctx->internal_state = rol64(ctx->internal_state, 1);
|
||||
swapbit(&ctx->internal_state, tempy);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Key creation for Retevis AP */
|
||||
void retevis_rc2_keystream_creation(dsd_state *state, char *input) {
|
||||
|
||||
unsigned char key1[64]; memset(key1, 0, sizeof(key1));
|
||||
unsigned char key2[64]; memset(key2, 0, sizeof(key2));
|
||||
|
||||
char buf[1024];
|
||||
strncpy(buf, input, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
char *pEnd;
|
||||
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||
uint64_t K3 = strtoull(pEnd, &pEnd, 16);
|
||||
uint64_t K4 = strtoull(pEnd, &pEnd, 16);
|
||||
|
||||
if (K3 != 0 || K4 != 0) //256-bit keys loaded as ASCII characters
|
||||
{
|
||||
//start loading K1, K2, K3, and K4 as ASCII to fill 64 bytes of key1
|
||||
int k = 0; uint8_t x = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K1 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K2 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K3 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
x = ((K4 >> (60-(i*4))) & 0xF);
|
||||
if (x >= 0 && x <= 9) //numbers 0-9
|
||||
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||
key1[k++] = x;
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "ASCII: ");
|
||||
// for (int i = 0; i < 64; i++)
|
||||
// fprintf (stderr, " %02X", key1[i]);
|
||||
// fprintf (stderr, "\n");
|
||||
|
||||
// Initialize RC2 context
|
||||
static CryptoContext rc2_ctx;
|
||||
create_keys_rc2(&rc2_ctx, key1, 64);
|
||||
|
||||
// Store context in DSD state
|
||||
state->rc2_context = malloc(sizeof(CryptoContext));
|
||||
memcpy(state->rc2_context, &rc2_ctx, sizeof(CryptoContext));
|
||||
|
||||
fprintf(stderr, "DMR RETEVIS AP (RC2) 256-bit Key %016llX%016llX%016llX%016llX with Forced Application\n",
|
||||
(unsigned long long)K1, (unsigned long long)K2, (unsigned long long)K3, (unsigned long long)K4);
|
||||
|
||||
state->retevis_ap = 1;
|
||||
}
|
||||
|
||||
else //128-bit loaded as reverse bytes
|
||||
{
|
||||
|
||||
u64_to_bytes_be(K1, &key1[0]);
|
||||
u64_to_bytes_be(K2, &key1[8]);
|
||||
|
||||
// reverse load the key bytes into key2
|
||||
for (int i=0;i<16;i++)
|
||||
key2[i] = key1[15-i];
|
||||
|
||||
// Initialize RC2 context
|
||||
static CryptoContext rc2_ctx;
|
||||
create_keys_rc2(&rc2_ctx, key2, 16);
|
||||
|
||||
// Store context in DSD state
|
||||
state->rc2_context = malloc(sizeof(CryptoContext));
|
||||
memcpy(state->rc2_context, &rc2_ctx, sizeof(CryptoContext));
|
||||
|
||||
fprintf(stderr, "DMR RETEVIS AP (RC2) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||
(unsigned long long)K1, (unsigned long long)K2);
|
||||
|
||||
state->retevis_ap = 1;
|
||||
}
|
||||
}
|
||||
146
src/crypt-tyt.c
146
src/crypt-tyt.c
@@ -159,96 +159,28 @@ 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[64]; memset(key1, 0, sizeof(key1));
|
||||
unsigned char key2[64]; memset(key2, 0, sizeof(key2));
|
||||
|
||||
unsigned char key1[16] = {0};
|
||||
unsigned char key2[16] = {0};
|
||||
|
||||
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;
|
||||
}
|
||||
u64_to_bytes_be(K1, &key1[0]);
|
||||
u64_to_bytes_be(K2, &key1[8]);
|
||||
|
||||
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++) key2[i] = key1[15-i];
|
||||
|
||||
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;
|
||||
}
|
||||
/* Create key schedule */
|
||||
create_keys(&ctx, key2, sizeof(key2));
|
||||
ctx.rounds = nbround;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
@@ -306,56 +238,4 @@ void tyt_ep_aes_keystream_creation(dsd_state * state, char * input)
|
||||
fprintf (stderr,"DMR TYT EP (AES-128) Key %016llX%016llX with Forced Application\n", K1, K2);
|
||||
state->tyt_ep = 1;
|
||||
|
||||
}
|
||||
|
||||
//connect systems 72-bit (9-byte) Extended Encryption //TODO: Move this later
|
||||
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24])
|
||||
{
|
||||
|
||||
char interleaved[72];
|
||||
memset (interleaved, 0, sizeof(interleaved));
|
||||
|
||||
//interleave the frame
|
||||
const int *w, *x, *y, *z;
|
||||
w = rW; x = rX; y = rY; z = rZ;
|
||||
|
||||
for (int8_t i = 0; i < 36; i++)
|
||||
{
|
||||
interleaved[(i*2)+0] = ambe_fr[*w][*x];
|
||||
interleaved[(i*2)+1] = ambe_fr[*y][*z];
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
uint8_t ks_bytes[9]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
uint8_t ks[72]; memset(ks, 0, sizeof(ks));
|
||||
|
||||
//keys are loaded in reverse byte order, stored in state->static_ks_bits[0]
|
||||
for (int i = 0; i < 9; i++)
|
||||
ks_bytes[i] = state->static_ks_bits[0][8-i];
|
||||
|
||||
//convert byte array into a bit array
|
||||
unpack_byte_array_into_bit_array(ks_bytes, ks, 9);
|
||||
|
||||
//apply keystream to interleave
|
||||
for (int8_t i = 0; i < 72; i++)
|
||||
interleaved[i] ^= ks[71-i];
|
||||
|
||||
//deinterleave back into ambe_fr frame
|
||||
w = rW; x = rX; y = rY; z = rZ;
|
||||
int k = 0;
|
||||
for (int8_t i = 0; i < 36; i++)
|
||||
{
|
||||
ambe_fr[*w][*x] = interleaved[k++];
|
||||
ambe_fr[*y][*z] = interleaved[k++];
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
108
src/dmr_block.c
108
src/dmr_block.c
@@ -335,7 +335,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
//The SAP found here is the actual SAP of the message (like a P25 ndary SAP, and can chain together according to ETSI)
|
||||
fprintf (stderr, " - SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string);
|
||||
|
||||
//p_sap 1 on mfid 10 MNIS Header
|
||||
//p_sap 1 on mfid 10 (moto) has been observed as the first block of LRRP data (unique fixed format?)
|
||||
if (p_mfid == 0x10 && p_sap == 1)
|
||||
{
|
||||
//add the header to the first 10 bytes of the storage (sans this header's CRC)
|
||||
@@ -365,42 +365,7 @@ 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 == 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)
|
||||
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)
|
||||
@@ -411,7 +376,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
else state->dmr_soR = 0x100;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n DMRA PDU ENC Header:");
|
||||
fprintf (stderr, "\n 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));
|
||||
|
||||
@@ -1042,21 +1007,6 @@ 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)
|
||||
@@ -1072,25 +1022,19 @@ 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 && mi != 0) fprintf (stderr, " MI(32): %08llX;", mi);
|
||||
if (alg != 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 == 4 || alg == 5)
|
||||
if (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)
|
||||
@@ -1105,54 +1049,30 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
decrypted_pdu = 1;
|
||||
}
|
||||
|
||||
else if (alg == 5 && akl == 1 && mi != 0) //AES-256 OFB
|
||||
if (alg == 5 && akl == 1) //AES-256
|
||||
{
|
||||
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
|
||||
else if (alg == 2 && R != 0) //Tait DES
|
||||
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;
|
||||
}
|
||||
|
||||
else if (alg == 4 && akl == 1 && mi != 0) //AES-128 OFB
|
||||
if (alg == 4 && akl == 1) //AES-128
|
||||
{
|
||||
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 key is available and keystream created, not ECB.
|
||||
//apply keystream here, only if alg is 1 or 4 AND key is available!
|
||||
if (alg == 1 && R != 0)
|
||||
{
|
||||
for (i = 0; i < end; i++)
|
||||
@@ -1164,17 +1084,15 @@ 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 && mi != 0)
|
||||
else if (alg == 4 && akl != 0)
|
||||
{
|
||||
for (i = 0; i < end; i++)
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[(i+16)%3096];
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
|
||||
}
|
||||
|
||||
else if (alg == 5 && akl != 0 && mi != 0)
|
||||
else if (alg == 5 && akl != 0)
|
||||
{
|
||||
for (i = 0; i < end; i++)
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[(i+16)%3096];
|
||||
state->dmr_pdu_sf[slot][i+start] ^= ob[i%3096];
|
||||
}
|
||||
|
||||
//BP key application
|
||||
|
||||
14
src/dmr_bs.c
14
src/dmr_bs.c
@@ -502,13 +502,6 @@ 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);
|
||||
@@ -961,13 +954,6 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||
}
|
||||
|
||||
if (state->csi_ee == 1)
|
||||
{
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||
}
|
||||
|
||||
#ifdef PRINT_AMBE72
|
||||
ambe2_codeword_print_i(opts, ambe_fr);
|
||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||
|
||||
@@ -72,15 +72,6 @@ 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)
|
||||
{
|
||||
@@ -319,8 +310,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, added Kirisun and KW Scrambler LC
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08 && fid != 0x0A && is_kenwood_sc == 0)
|
||||
//removed tait from the list, added hytera 0x08
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08 && is_kenwood_sc == 0)
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KYEL);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KYEL);
|
||||
@@ -663,7 +654,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
}
|
||||
|
||||
//should rework this back into the upper portion
|
||||
if (fid == 0x0A) fprintf (stderr, "Kirisun ");
|
||||
if (fid == 0x68) fprintf (stderr, "Hytera ");
|
||||
if (is_xpt) fprintf (stderr, "XPT ");
|
||||
if (fid == 0x68 && flco == 0x00)
|
||||
|
||||
90
src/dmr_le.c
90
src/dmr_le.c
@@ -14,6 +14,23 @@ 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);
|
||||
@@ -219,23 +236,6 @@ 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,23 +266,6 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -407,41 +390,6 @@ 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)
|
||||
@@ -518,7 +466,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->forced_alg_id == 0)
|
||||
if (state->M == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
@@ -544,7 +492,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->forced_alg_id == 0)
|
||||
if (state->M == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
|
||||
24
src/dmr_ms.c
24
src/dmr_ms.c
@@ -167,16 +167,6 @@ 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];
|
||||
|
||||
@@ -263,13 +253,6 @@ 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);
|
||||
@@ -581,13 +564,6 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||
}
|
||||
|
||||
if (state->csi_ee == 1)
|
||||
{
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||
}
|
||||
|
||||
#ifdef PRINT_AMBE72
|
||||
ambe2_codeword_print_i(opts, ambe_fr);
|
||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||
|
||||
@@ -482,34 +482,6 @@ void decode_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t *
|
||||
sprintf (state->dmr_lrrp_gps[slot], "ETSI TMS SRC: %d; DST: %d; ", src24, dst24);
|
||||
utf16_to_text(state, 1, len, input+28);
|
||||
}
|
||||
//Vertex Standard TMS Port
|
||||
else if (port1 == 5007 && port2 == 5007)
|
||||
{
|
||||
|
||||
//get pad amount to see where to stop parsing UTF16 text
|
||||
int pad = state->data_block_poc[slot];
|
||||
|
||||
//sanity check
|
||||
if (len > (50+pad))
|
||||
len = len - pad - 50;
|
||||
|
||||
fprintf (stderr, "VTX STD TMS; ");
|
||||
|
||||
//+28, get 9 bytes for unknown "header" information
|
||||
//unknown elements 0E0002000000000000, could include a len value or type (utf-16, utf-8, is07?)
|
||||
//the sample has a len of 8 utf-16 chars, only way to get that is on the 2 if not byte aligned (1000)
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
// fprintf (stderr, "Len: %03d; ", len);
|
||||
fprintf (stderr, "??: ");
|
||||
for (int i = 0; i < 9; i++)
|
||||
fprintf (stderr, "%02X", input[i+28]);
|
||||
fprintf (stderr, "; Text: ");
|
||||
}
|
||||
|
||||
sprintf (state->dmr_lrrp_gps[slot], "VTX TMS SRC: %d; DST: %d; ", src24, dst24);
|
||||
utf16_to_text(state, 1, len, input+49);
|
||||
}
|
||||
else if (port1 == 5017 && port2 == 5017)
|
||||
{
|
||||
//sanity check
|
||||
|
||||
92
src/dmr_pi.c
92
src/dmr_pi.c
@@ -12,6 +12,7 @@
|
||||
|
||||
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];
|
||||
|
||||
@@ -25,57 +26,6 @@ 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)
|
||||
@@ -473,13 +423,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%len];
|
||||
if (bit) mi[i] ^= taps[i%5];
|
||||
mi[i] |= bit;
|
||||
|
||||
}
|
||||
|
||||
unsigned long long int mi_value = 0;
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
for (uint8_t i = 0; i < 5; i++)
|
||||
{
|
||||
mi_value <<= 8;
|
||||
mi_value |= mi[i];
|
||||
@@ -520,38 +470,4 @@ void hytera_enhanced_alg_refresh(dsd_state * state)
|
||||
if (state->currentslot == 0)
|
||||
state->payload_mi = mi_value;
|
||||
else state->payload_miR = mi_value;
|
||||
}
|
||||
|
||||
uint32_t kirisun_lfsr(unsigned long long int mi)
|
||||
{
|
||||
|
||||
uint32_t taps = 0xD459C4F1;
|
||||
uint32_t lfsr = (uint32_t)mi;
|
||||
uint32_t new_mi = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
||||
uint8_t byte = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint32_t temp = (lfsr << 1);
|
||||
uint8_t msb = (lfsr >> 31) & 1;
|
||||
|
||||
if (msb)
|
||||
{
|
||||
byte |= (1 << j);
|
||||
lfsr = temp ^ taps;
|
||||
}
|
||||
else lfsr = temp; //was previously temp ^ 1, but that isn't a primitive
|
||||
}
|
||||
|
||||
new_mi <<=8;
|
||||
new_mi |= byte;
|
||||
|
||||
}
|
||||
|
||||
return new_mi;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -794,18 +794,22 @@ 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, " ");
|
||||
|
||||
//Encode to UTF-8
|
||||
ptr += utf8_encode(character, alias_string+ptr);
|
||||
if (character == 0)
|
||||
strcat (alias_string, " ");
|
||||
else if (character >= 0x20 && character <= 0xFE)
|
||||
strcat (alias_string, ch);
|
||||
else
|
||||
strcat (alias_string, "*");
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " [%04X], ", character);
|
||||
|
||||
@@ -137,11 +137,9 @@ void openPulseInput(dsd_opts * opts)
|
||||
lt.maxlength = -1;
|
||||
lt.prebuf = -1;
|
||||
lt.tlength = -1;
|
||||
// if (opts->m17encoder == 1)
|
||||
// opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err);
|
||||
// else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||
|
||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||
if (opts->m17encoder == 1)
|
||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err);
|
||||
else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
@@ -189,14 +187,6 @@ void parse_pulse_output_string (dsd_opts * opts, char * input)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// macOS does not support OSS (/dev/dsp).
|
||||
// Provide a stub so callers can link while using Pulse/CoreAudio backends.
|
||||
void openOSSOutput(dsd_opts *opts)
|
||||
{
|
||||
(void)opts;
|
||||
}
|
||||
#else
|
||||
void openOSSOutput (dsd_opts * opts)
|
||||
{
|
||||
int fmt;
|
||||
@@ -215,7 +205,6 @@ void openOSSOutput (dsd_opts * opts)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
fmt = 0;
|
||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
@@ -312,7 +301,6 @@ void openOSSOutput (dsd_opts * opts)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
processAudio (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
@@ -100,7 +100,7 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
||||
encL = 0;
|
||||
}
|
||||
}
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||
{
|
||||
//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 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
||||
else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||
{
|
||||
//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 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
else if (state->payload_algid == 0x84 || state->payload_algid == 0x89 || state->nxdn_cipher_type == 0x3)
|
||||
{
|
||||
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 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||
else if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||
{
|
||||
//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 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
||||
else if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||
{
|
||||
//going to need a better check for this later on, or seperated keys or something
|
||||
if (state->aes_key_loaded[1] == 1)
|
||||
|
||||
@@ -695,7 +695,7 @@ void watchdog_event_current (dsd_opts * opts, dsd_state * state, uint8_t slot)
|
||||
|
||||
if (state->ea_mode == 1)
|
||||
{
|
||||
sprintf (event_string, "%s %s %s TGT: %07d; SRC: %07d; LCN: %02d; SITE: %d:%d.%04X; %s; ", datestr, timestr, sys_string, target_id, source_id, channel, sys_id1, sys_id2, sys_id3, sup_str);
|
||||
sprintf (event_string, "%s %s %s TGT: %07d; SRC: %07d; LCN: %02d; SITE: %d:%d.%04X; %s;", datestr, timestr, sys_string, target_id, source_id, channel, sys_id1, sys_id2, sys_id3, sup_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
263
src/dsd_file.c
263
src/dsd_file.c
@@ -18,7 +18,6 @@
|
||||
#include "dsd.h"
|
||||
#include "p25p1_const.h" //for imbe fr (7200)
|
||||
#include "dmr_const.h" //for ambe+2 fr
|
||||
#include "bp.h" //for bp key table
|
||||
|
||||
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
{
|
||||
@@ -929,12 +928,9 @@ uint16_t parse_raw_user_string (char * input, uint8_t * output)
|
||||
return len;
|
||||
}
|
||||
|
||||
//DMRA late entry items
|
||||
static int ambe2_counter;
|
||||
static int dmra_le;
|
||||
|
||||
uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str, uint8_t * ks, uint16_t ks_idx, uint8_t dmra, uint8_t is_enc, uint8_t ks_available)
|
||||
{
|
||||
UNUSED(opts);
|
||||
|
||||
char ambe_fr[4][24]; memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
uint8_t dibit_pair = 0;
|
||||
@@ -980,39 +976,6 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
|
||||
|
||||
}
|
||||
|
||||
//if using DMRA Late Entry IV mechanics, evaluate for IV
|
||||
if (dmra_le)
|
||||
{
|
||||
|
||||
//make a copy of ambe_fr codeword 3 (MI fragment)
|
||||
uint8_t c3[24]; memset (c3, 0, sizeof(c3));
|
||||
for (int i = 0; i < 24; i++)
|
||||
c3[i] = ambe_fr[3][i];
|
||||
|
||||
//force slot to 0
|
||||
state->currentslot = 0;
|
||||
|
||||
uint8_t c3_hex = (uint64_t)ConvertBitIntoBytes(c3, 4);
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "\n AMBE#: %02d / %d / %d; F: %X;", ambe2_counter, ambe2_counter/3, ambe2_counter%3, c3_hex);
|
||||
|
||||
//use div and mod 3 to set current storage fragment
|
||||
state->late_entry_mi_fragment[0][(ambe2_counter/3)+1][ambe2_counter%3] = c3_hex;
|
||||
|
||||
//run LFSR evaluate stored codewords for matching IV or replace if not match or not set
|
||||
if (ambe2_counter == 17)
|
||||
{
|
||||
if (state->payload_mi != 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
LFSR(state);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
dmr_late_entry_mi (opts, state);
|
||||
}
|
||||
}
|
||||
|
||||
char ambe_d[49]; memset(ambe_d, 0, sizeof(ambe_d));
|
||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr);
|
||||
state->errs2 = state->errs;
|
||||
@@ -1089,6 +1052,7 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
|
||||
|
||||
uint16_t imbe_str_to_decode(dsd_opts * opts, dsd_state * state, char * imbe_str, uint8_t * ks, uint16_t ks_idx, uint8_t is_enc, uint8_t ks_available)
|
||||
{
|
||||
UNUSED(opts);
|
||||
|
||||
char imbe_fr[8][23]; memset (imbe_fr, 0, sizeof(imbe_fr));
|
||||
uint8_t dibit_pair = 0;
|
||||
@@ -1235,16 +1199,6 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
state->synctype = -1;
|
||||
state->lastsynctype = -1;
|
||||
|
||||
//reset encryption variables
|
||||
state->payload_mi = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->R = 0;
|
||||
state->aes_key_loaded[0] = 0;
|
||||
}
|
||||
|
||||
//watchdog for event history
|
||||
watchdog_event_history(opts, state, 0);
|
||||
watchdog_event_current(opts, state, 0);
|
||||
@@ -1256,12 +1210,6 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t ks_i[3000]; memset (ks_i, 0, sizeof(ks_i));
|
||||
uint16_t ks_idx_i = 808; //keystream index value IMBE (start at 808 for out of order ESS)
|
||||
int imbe_counter = 0; //count IMBE frames for when to skip 2 bytes of ks and juggle keystreams
|
||||
|
||||
//Used in conjunction with DMR's DMRA Late Entry IV
|
||||
ambe2_counter = 0; //count AMBE+2 frames for DMRA late entry IV mechanics (static)
|
||||
dmra_le = 0; //whether or not to attempt looking for the DMRA Late Entry
|
||||
if (state->forced_alg_id != 0)
|
||||
state->payload_mi = 0;
|
||||
|
||||
source_size = fread (source_str, 1, 0x100000, opts->mbe_in_f);
|
||||
|
||||
@@ -1396,77 +1344,6 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//if forcing a DMRA EP mode, turn on dmra_le and set alg here
|
||||
if (state->forced_alg_id >= 0x21 && state->forced_alg_id <= 0x25)
|
||||
{
|
||||
is_dmra = 1;
|
||||
dmra_le = 1;
|
||||
is_enc = 1;
|
||||
alg_id = state->forced_alg_id;
|
||||
state->payload_algid = alg_id;
|
||||
rc4_db = 256;
|
||||
rc4_mod = 9;
|
||||
|
||||
//since we can't keyring on a forced alg, we can perhaps look it up
|
||||
//via the TO field for the TG value, as long as it isn't greated than 0x1FFFF (upper bound of the array)
|
||||
if (state->keyloader == 1 && state->lasttg != 0 && state->lasttg < 0x1FFFF && state->rkey_array[state->lasttg] != 0)
|
||||
state->R = state->rkey_array[state->lasttg];
|
||||
|
||||
if (alg_id == 0x21 && state->R != 0 && state->payload_mi != 0)
|
||||
{
|
||||
|
||||
//test when we don't have an encryption_mi in the .mbe file for DMR
|
||||
//TODO: Handle multi keystream creation with a new function
|
||||
uint8_t ks_bytes[375]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
uint8_t kiv[32]; memset(kiv, 0, sizeof(kiv));
|
||||
|
||||
//load key into key portion of kiv
|
||||
kiv[0] = ((state->R & 0xFF00000000) >> 32);
|
||||
kiv[1] = ((state->R & 0xFF000000) >> 24);
|
||||
kiv[2] = ((state->R & 0xFF0000) >> 16);
|
||||
kiv[3] = ((state->R & 0xFF00) >> 8);
|
||||
kiv[4] = ((state->R & 0xFF) >> 0);
|
||||
|
||||
//load IV from late entry state->payload_mi
|
||||
kiv[5] = ((state->payload_mi & 0xFF000000) >> 24);
|
||||
kiv[6] = ((state->payload_mi & 0xFF0000) >> 16);
|
||||
kiv[7] = ((state->payload_mi & 0xFF00) >> 8);
|
||||
kiv[8] = ((state->payload_mi & 0xFF) >> 0);
|
||||
|
||||
rc4_block_output (rc4_db, rc4_mod, 200, kiv, ks_bytes);
|
||||
unpack_byte_array_into_bit_array(ks_bytes, ks, 200);
|
||||
|
||||
ks_available = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//TODO: This
|
||||
else if (state->forced_alg_id == 1) //Basic Privacy
|
||||
{
|
||||
//This is where the key loaded comes into play for moto vs hytera vs scrambler
|
||||
if (state->K != 0)
|
||||
{
|
||||
uint64_t k = 0;
|
||||
k = BPK[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
k <<= 1;
|
||||
k += (k >> 48) & 1;
|
||||
|
||||
//load that into ks
|
||||
for (int i = 0; i < 18*49; i++)
|
||||
ks[i] = (k >> (i%49)) & 1;
|
||||
}
|
||||
else if (state->H != 0)
|
||||
{
|
||||
//Hytera BP
|
||||
}
|
||||
else if (state->R != 0)
|
||||
{
|
||||
//NXDN Scrambler
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp ("to", str_buffer, 2) == 0)
|
||||
{
|
||||
str_buffer = strtok(NULL, " : \""); //next value after any : "" string
|
||||
@@ -1568,9 +1445,9 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//TODO: Handle multi keystream creation with a new function
|
||||
uint8_t ks_bytes[375]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
uint8_t kiv[32]; memset(kiv, 0, sizeof(kiv));
|
||||
uint8_t kiv[15]; memset(kiv, 0, sizeof(kiv));
|
||||
|
||||
//RC4 (v1 tested and working on P25, v2 should be okay now)
|
||||
//Test: Setup a simple RC4 for now (working)
|
||||
if ( (alg_id == 0xAA || alg_id == 0x21) && state->R != 0 )
|
||||
{
|
||||
|
||||
@@ -1603,113 +1480,19 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
ks_available = 1;
|
||||
|
||||
}
|
||||
|
||||
//P25 DES (v1 tested and working on P1, v2 should be okay now)
|
||||
else if (alg_id == 0x81 && state->R != 0)
|
||||
{
|
||||
} //end test
|
||||
|
||||
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
|
||||
//NOTE: Regarding SDRTrunk .mbe format, the ESS Encryption Sync
|
||||
//is in the correct location on P25p2, but for P25p1, the ESS
|
||||
//information preceeds LDU2, but should be AFTER the LDU2 IMBE frames,
|
||||
//so, for now, we utilize a reverse lfsr function (Crypthings coming in handy)
|
||||
//and recover the previous LFSR and make two keystreams in order
|
||||
//to properly decrypt the initial frame, and then juggle the
|
||||
//keystreams in code to provide a smooth decryption session of P25p1.
|
||||
|
||||
if (protocol == 1) //Phase 1 IMBE start on 19 for DES-OFB (8 discard + 9 LCW + 2 reserved)
|
||||
unpack_byte_array_into_bit_array(ks_bytes+19, ks, 256-19); //unpack starting after discard
|
||||
else if (protocol == 2) //Phase 2 AMBE+2 start on 8 after discard round for DES-OFB
|
||||
unpack_byte_array_into_bit_array(ks_bytes+8, ks, 256-8); //unpack starting after discard
|
||||
|
||||
//reverse lfsr on IV and create keystream with that as well
|
||||
//due to out of order execution on P25p1 ESS sync.
|
||||
if (protocol == 1 && version == 1)
|
||||
{
|
||||
|
||||
//load the str_buffer into the IV portion of kiv (just borrowing for DES)
|
||||
parse_raw_user_string(str_buffer, kiv+5);
|
||||
|
||||
reverse_lfsr_64_to_len (opts, kiv+5, 64);
|
||||
|
||||
//convert bytes back into value
|
||||
iv_hex = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
iv_hex <<= 8;
|
||||
iv_hex |= kiv[i+5];
|
||||
}
|
||||
|
||||
memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
|
||||
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
|
||||
|
||||
unpack_byte_array_into_bit_array(ks_bytes+19, ks_i, 256-19); //unpack starting after discard
|
||||
}
|
||||
|
||||
ks_available = 1;
|
||||
|
||||
}
|
||||
|
||||
//P25 AES (v1 and v2 tested working on P1)
|
||||
else if ( (alg_id == 0x84 || alg_id == 0x89) && state->aes_key_loaded[0] == 1 )
|
||||
{
|
||||
|
||||
uint8_t aes_key[32];
|
||||
memset(aes_key, 0, sizeof(aes_key));
|
||||
|
||||
//Load key from A1 - A4
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
|
||||
aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
|
||||
aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
|
||||
aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
|
||||
}
|
||||
|
||||
uint8_t aes_iv[16];
|
||||
memset(aes_iv, 0, sizeof(aes_iv));
|
||||
|
||||
//load the str_buffer into the IV portion of aes_iv
|
||||
parse_raw_user_string(str_buffer, aes_iv);
|
||||
|
||||
//backup copy of current IV to reverse and expand, if needed
|
||||
uint8_t aes_last_iv[16];
|
||||
memset(aes_last_iv, 0, sizeof(aes_last_iv));
|
||||
for (int i = 0; i < 8; i++)
|
||||
aes_last_iv[i] = aes_iv[i];
|
||||
|
||||
//Resolve the longer IV from the shorter one
|
||||
lfsr_64_to_128(aes_iv);
|
||||
|
||||
if (alg_id == 0x89) //128, or 256
|
||||
aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 0, 16); //16*16=256
|
||||
else aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 2, 16); //16*16=256
|
||||
|
||||
if (protocol == 1) //Phase 1 IMBE start on 27 for AES-OFB (16 discard + 9 LCW + 2 reserved)
|
||||
unpack_byte_array_into_bit_array(ks_bytes+27, ks, 256-27); //unpack starting after discard
|
||||
else if (protocol == 2) //Phase 2 AMBE+2 start on 16 after discard round for AES-OFB
|
||||
unpack_byte_array_into_bit_array(ks_bytes+16, ks, 256-16); //unpack starting after discard
|
||||
|
||||
//reverse lfsr on IV and create keystream with that as well
|
||||
//due to out of order execution on P25p1 ESS sync.
|
||||
if (protocol == 1 && version == 1)
|
||||
{
|
||||
|
||||
reverse_lfsr_64_to_len (opts, aes_last_iv, 64);
|
||||
|
||||
//Resolve the longer IV from the shorter one
|
||||
lfsr_64_to_128(aes_last_iv);
|
||||
|
||||
memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||
|
||||
if (alg_id == 0x89) //128, or 256
|
||||
aes_ofb_keystream_output(aes_last_iv, aes_key, ks_bytes, 0, 16); //16*16=256
|
||||
else aes_ofb_keystream_output(aes_last_iv, aes_key, ks_bytes, 2, 16); //16*16=256
|
||||
|
||||
unpack_byte_array_into_bit_array(ks_bytes+27, ks_i, 256-27); //unpack starting after discard
|
||||
}
|
||||
|
||||
ks_available = 1;
|
||||
|
||||
}
|
||||
|
||||
//Pull request: https://github.com/DSheirer/sdrtrunk/pull/2273
|
||||
//Merged into SDRTrunk nightly so should be able to handle this better now
|
||||
//Update: There is a pull request available now, and using a version value,
|
||||
//we will be able to do either format (ESS out of order vs ESS in correct order)
|
||||
|
||||
//reset ks_idx to 0
|
||||
ks_idx = 0;
|
||||
@@ -1733,9 +1516,6 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
imbe_counter++;
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "\n IMBE# %02d; KS_IDX: %d; KS_IDX_I: %d; ", imbe_counter, ks_idx, ks_idx_i);
|
||||
|
||||
//36 hex characters on 'hex' which is the IMBE interleaved C codewords
|
||||
if (version == 1)
|
||||
ks_idx_i = imbe_str_to_decode(opts, state, str_buffer, ks_i, ks_idx_i, is_enc, ks_available);
|
||||
@@ -1743,10 +1523,7 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//skip LSD bits in-between these two IMBE voice frames
|
||||
if (imbe_counter == 8 || imbe_counter == 17)
|
||||
{
|
||||
ks_idx_i += 16;
|
||||
ks_idx += 16;
|
||||
}
|
||||
|
||||
//juggle keystreams and reset the I counter (if version 1)
|
||||
if (imbe_counter == 9 && version == 1)
|
||||
@@ -1767,7 +1544,7 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "\n IMBE# %02d; KS_IDX: %d; KS_IDX_I: %d; ", imbe_counter, ks_idx, ks_idx_i);
|
||||
// fprintf (stderr, " # %02d; KS_IDX_I: %04d;", imbe_counter, ks_idx_i);
|
||||
|
||||
//debug
|
||||
// if (is_enc == 1 && ks_available == 0)
|
||||
@@ -1790,16 +1567,6 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
||||
// else if (is_enc == 1 && ks_available == 1)
|
||||
// fprintf (stderr, " Enc Play;");
|
||||
|
||||
//increment AMBE+2 counter
|
||||
ambe2_counter++;
|
||||
|
||||
//reset if over for DMR 18 AMBE+2 frames
|
||||
if (dmra_le && ambe2_counter == 18)
|
||||
{
|
||||
ambe2_counter = 0;
|
||||
ks_idx = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#include "p25p1_check_nid.h"
|
||||
|
||||
void
|
||||
printFrameInfo (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
@@ -260,10 +262,21 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
processYSF(opts, state);
|
||||
return;
|
||||
}
|
||||
//M17 STR
|
||||
else if (state->synctype == 16)
|
||||
//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) )
|
||||
{
|
||||
processM17STR(opts, state);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
//P25 P2
|
||||
|
||||
@@ -162,6 +162,7 @@ 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?
|
||||
@@ -207,8 +208,9 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
t = 0;
|
||||
synctest10[10] = 0;
|
||||
synctest[24] = 0;
|
||||
synctest8[8] = 0;
|
||||
synctest8[8] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin)
|
||||
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;
|
||||
@@ -417,8 +419,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
|
||||
//if using an rtl input method, do not look for sync patterns if the rms value is lower than our 'soft squelch' level
|
||||
if (opts->audio_in_type == 3 && opts->rtl_rms < opts->rtl_squelch_level)
|
||||
//if using an rtl input method, do not look for sync patterns if the pwr value is lower than our 'soft squelch' level
|
||||
if (opts->audio_in_type == 3 && opts->rtl_pwr < opts->rtl_squelch_level)
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1 || opts->frame_dpmr == 1 || opts->frame_m17 == 1)
|
||||
{
|
||||
@@ -564,24 +566,139 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
//end YSF sync
|
||||
|
||||
//M17 Sync -- Just STR
|
||||
//M17 Sync -- Just STR and LSF for now
|
||||
strncpy(synctest16, (synctest_p - 15), 16);
|
||||
strncpy(synctest8, (synctest_p - 7), 8);
|
||||
if(opts->frame_m17 == 1)
|
||||
{
|
||||
if (strcmp(synctest8, M17_STR) == 0)
|
||||
//preambles will skip dibits in an attempt to prime the
|
||||
//demodulator but not attempt any decoding
|
||||
if (strcmp(synctest8, M17_PRE) == 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)
|
||||
if (opts->inverted_m17 == 0)
|
||||
{
|
||||
state->lastsynctype = 16;
|
||||
return (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");
|
||||
}
|
||||
state->lastsynctype = 16;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
//end M17
|
||||
|
||||
405
src/dsd_main.c
405
src/dsd_main.c
@@ -538,6 +538,7 @@
|
||||
//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;
|
||||
@@ -551,18 +552,13 @@
|
||||
state->m17_enc = 0;
|
||||
state->m17_enc_st = 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;
|
||||
|
||||
//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", "");
|
||||
|
||||
//set float temp buffer to baseline
|
||||
memset (state->audio_out_temp_buf, 0.0f, sizeof(state->audio_out_temp_buf));
|
||||
@@ -678,24 +674,29 @@
|
||||
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;
|
||||
//all RTL user options -- enabled AGC by default due to weak signal related issues
|
||||
opts->rtl_dev_index = 0; //choose which device we want by index number
|
||||
opts->rtl_gain_value = 0; //mid value, 0 - AGC - 0 to 49 acceptable values
|
||||
opts->rtl_squelch_level = 100; //100 by default, but only affects NXDN and dPMR during framesync test, compared to RMS value
|
||||
opts->rtl_squelch_level = 10000; //default scaled for rtl_pwr (RMS^2 proxy); ~100 RMS equivalent
|
||||
opts->rtl_volume_multiplier = 2; //sample multiplier; This multiplies the sample value to produce a higher 'inlvl' for the demodulator
|
||||
opts->rtl_udp_port = 0; //set UDP port for RTL remote -- 0 by default, will be making this optional for some external/legacy use cases (edacs-fm, etc)
|
||||
opts->rtl_bandwidth = 12; //default is 12, reverted back to normal on this (no inherent benefit)
|
||||
opts->rtlsdr_ppm_error = 0; //initialize ppm with 0 value;
|
||||
opts->rtlsdr_center_freq = 850000000; //set to an initial value (if user is using a channel map, then they won't need to specify anything other than -i rtl if desired)
|
||||
opts->rtl_started = 0;
|
||||
opts->rtl_rms = 0; //root means square power level on rtl input signal
|
||||
opts->rtl_pwr = 0; // mean power approximation level on rtl input signal
|
||||
//end RTL user options
|
||||
opts->pulse_raw_rate_in = 48000;
|
||||
opts->pulse_raw_rate_out = 48000;//
|
||||
@@ -761,6 +762,12 @@
|
||||
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++
|
||||
@@ -1034,7 +1041,7 @@
|
||||
state->K2 = 0;
|
||||
state->K3 = 0;
|
||||
state->K4 = 0;
|
||||
state->forced_alg_id = 0; //force key priority over settings from fid/so
|
||||
state->M = 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
|
||||
@@ -1057,9 +1064,6 @@
|
||||
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;
|
||||
@@ -1209,7 +1213,6 @@
|
||||
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;
|
||||
@@ -1308,16 +1311,22 @@
|
||||
//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", "");
|
||||
@@ -1325,19 +1334,10 @@
|
||||
|
||||
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,6 +1395,8 @@
|
||||
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");
|
||||
@@ -1417,6 +1419,8 @@
|
||||
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");
|
||||
@@ -1457,12 +1461,34 @@
|
||||
printf (" gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)\n");
|
||||
printf (" ppm <num> RTL-SDR PPM Error (default = 0)\n");
|
||||
printf (" bw <num> RTL-SDR Bandwidth kHz (default = 12)(4, 6, 8, 12, 16, 24) \n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)\n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level vs PWR Value (Optional)\n");
|
||||
// printf (" udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)\n"); //NOTE: This is still available as an option in the ncurses menu
|
||||
printf (" vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)\n");
|
||||
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");
|
||||
@@ -1474,6 +1500,7 @@
|
||||
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");
|
||||
@@ -1489,15 +1516,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");
|
||||
@@ -1512,17 +1539,18 @@
|
||||
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");
|
||||
printf (" -H <hex> Manually Enter AES-128, AES-256, or Kirisun-256 Hex Key (see example below)\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 (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
||||
@@ -1533,28 +1561,14 @@
|
||||
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) 128 or 256 bit AP Hex Key (see example below)\n");
|
||||
printf (" -! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) 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");
|
||||
@@ -1566,8 +1580,6 @@
|
||||
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");
|
||||
@@ -1580,8 +1592,6 @@
|
||||
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");
|
||||
@@ -1634,8 +1644,8 @@
|
||||
open_rtlsdr_stream(opts);
|
||||
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
|
||||
// #ifdef __arm__
|
||||
// fprintf (stderr, "WARNING: RMS Function is Disabled on ARM Devices (Raspberry Pi) due to High CPU use. \n");
|
||||
// fprintf (stderr, "RMS/Squelch Functionality for NXDN, dPMR, EDACS Analog, M17 and Raw Audio Monitor are unavailable and these modes will not function properly. \n");
|
||||
// fprintf (stderr, "WARNING: PWR Function is Disabled on ARM Devices (Raspberry Pi) due to High CPU use. \n");
|
||||
// fprintf (stderr, "PWR/Squelch Functionality for NXDN, dPMR, EDACS Analog, M17 and Raw Audio Monitor are unavailable and these modes will not function properly. \n");
|
||||
// if (opts->monitor_input_audio == 1) opts->monitor_input_audio = 0;
|
||||
// opts->rtl_squelch_level = 0;
|
||||
// #endif
|
||||
@@ -1809,6 +1819,9 @@
|
||||
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);
|
||||
@@ -1886,7 +1899,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:G:D:L:V:U:YK:b:H:X:M:NQ:WrlZTF@:!:01:2:345:6:^:7:8_:9: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:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF!:01:2:345:6:7:89:Ek:I:J:O")) != -1)
|
||||
{
|
||||
|
||||
switch (c)
|
||||
@@ -1900,9 +1913,8 @@
|
||||
opts.call_alert = 1;
|
||||
break;
|
||||
|
||||
//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
|
||||
//Free'd up switches include: j, O,
|
||||
//
|
||||
|
||||
//make sure to put a colon : after each if they need an argument
|
||||
//or remove colon if no argument required
|
||||
@@ -1922,6 +1934,20 @@
|
||||
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);
|
||||
@@ -1936,14 +1962,9 @@
|
||||
|
||||
//rc4 enforcement on DMR (due to missing the PI header)
|
||||
case '0':
|
||||
state.forced_alg_id = 0x21;
|
||||
state.M = 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':
|
||||
@@ -1966,24 +1987,12 @@
|
||||
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);
|
||||
@@ -1994,11 +2003,6 @@
|
||||
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);
|
||||
@@ -2201,15 +2205,7 @@
|
||||
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
|
||||
@@ -2241,7 +2237,7 @@
|
||||
break;
|
||||
|
||||
case '4':
|
||||
state.forced_alg_id = 1;
|
||||
state.M = 1;
|
||||
fprintf (stderr,"Force Privacy Key over Encryption Identifiers (DMR BP and NXDN Scrambler) \n");
|
||||
break;
|
||||
|
||||
@@ -2978,6 +2974,40 @@
|
||||
//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':
|
||||
@@ -3077,6 +3107,11 @@
|
||||
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':
|
||||
@@ -3104,6 +3139,48 @@
|
||||
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: ");
|
||||
@@ -3392,23 +3469,18 @@
|
||||
//to a variable config, it cannot be the input as well
|
||||
|
||||
|
||||
#ifndef __APPLE__
|
||||
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
||||
speed = 48000; //hardset to 48000
|
||||
if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
@@ -3442,31 +3514,24 @@
|
||||
|
||||
opts.audio_in_type = 5; //5 will become OSS input type
|
||||
}
|
||||
#endif
|
||||
|
||||
//check for OSS output
|
||||
#ifndef __APPLE__
|
||||
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
if((strncmp(opts.audio_out_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//this will only open OSS output if its listed as a type
|
||||
//changed to this so I could call it freely inside of ncurses terminal
|
||||
#ifndef __APPLE__
|
||||
if (opts.playfiles == 0)
|
||||
openOSSOutput(&opts);
|
||||
#endif
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
@@ -3478,10 +3543,8 @@
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
if (opts.audio_out_type == 0)
|
||||
openPulseOutput(&opts);
|
||||
#ifndef __APPLE__
|
||||
else if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0))
|
||||
openOSSOutput(&opts); //open after split == 1 so it will open and playback at the proper speed
|
||||
#endif
|
||||
}
|
||||
|
||||
//this particular if-elseif-else could be rewritten to be a lot neater and simpler
|
||||
@@ -3515,12 +3578,134 @@
|
||||
signal(SIGINT, handler);
|
||||
signal(SIGTERM, handler);
|
||||
|
||||
//read in any user supplied M17 CAN and/or CSD data
|
||||
if((strncmp(state.m17dat, "M17", 3) == 0))
|
||||
{
|
||||
//read in values
|
||||
//string in format of M17:can:src_csd:dst_csd:input_rate
|
||||
|
||||
//check and capatalize any letters in the CSD
|
||||
for (int i = 0; state.m17dat[i]!='\0'; i++)
|
||||
{
|
||||
if(state.m17dat[i] >= 'a' && state.m17dat[i] <= 'z')
|
||||
state.m17dat[i] = state.m17dat[i] -32;
|
||||
}
|
||||
|
||||
fprintf (stderr, "M17 User Data: ");
|
||||
char * curr;
|
||||
|
||||
// if((strncmp(state.m17dat, "M17", 3) == 0))
|
||||
// goto M17END;
|
||||
|
||||
curr = strtok(state.m17dat, ":"); //should be 'M17'
|
||||
if (curr != NULL) ; //continue
|
||||
else goto M17END; //end early with preset values
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 channel access number
|
||||
if (curr != NULL)
|
||||
state.m17_can_en = atoi(curr);
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 src address
|
||||
if (curr != NULL)
|
||||
{
|
||||
strncpy (state.str50c, curr, 9); //only read first 9
|
||||
state.str50c[9] = '\0';
|
||||
}
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 dst address
|
||||
if (curr != NULL)
|
||||
{
|
||||
strncpy (state.str50b, curr, 9); //only read first 9
|
||||
state.str50b[9] = '\0';
|
||||
}
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 input audio rate
|
||||
if (curr != NULL)
|
||||
state.m17_rate = atoi(curr);
|
||||
|
||||
curr = strtok(NULL, ":"); //m17 vox enable
|
||||
if (curr != NULL)
|
||||
state.m17_vox = atoi(curr);
|
||||
|
||||
// curr = strtok(NULL, ":"); //moved to in and out methods
|
||||
// if (curr != NULL)
|
||||
// opts.m17_use_ip = atoi(curr);
|
||||
|
||||
M17END: ; //do nothing
|
||||
|
||||
//check to make sure can value is no greater than 15 (4 bit value)
|
||||
if (state.m17_can_en > 15)
|
||||
state.m17_can_en = 15;
|
||||
|
||||
//if vox is greater than 1, assume user meant 'yes' and set to one
|
||||
if (state.m17_vox > 1)
|
||||
state.m17_vox = 1;
|
||||
|
||||
//debug print m17dat string
|
||||
// fprintf (stderr, " %s;", state.m17dat);
|
||||
|
||||
fprintf (stderr, " M17:%d:%s:%s:%d;", state.m17_can_en, state.str50c, state.str50b, state.m17_rate);
|
||||
if (state.m17_vox == 1) fprintf (stderr, "VOX;");
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
|
||||
playMbeFiles (&opts, &state, argc, argv);
|
||||
}
|
||||
|
||||
else if (opts.m17encoder == 1)
|
||||
{
|
||||
//disable RRC filter for now
|
||||
opts.use_cosine_filter = 0;
|
||||
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
|
||||
//open any inputs, if not alread opened, OSS input and output already handled
|
||||
if (opts.audio_in_type == 0) openPulseInput(&opts);
|
||||
|
||||
#ifdef USE_RTLSDR
|
||||
else if(opts.audio_in_type == 3)
|
||||
{
|
||||
open_rtlsdr_stream(&opts);
|
||||
opts.rtl_started = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
//All input and output now opened and handled correctly, so let's not break things by tweaking
|
||||
encodeM17STR(&opts, &state);
|
||||
}
|
||||
|
||||
else if (opts.m17encoderbrt == 1)
|
||||
{
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
encodeM17BRT(&opts, &state);
|
||||
}
|
||||
|
||||
else if (opts.m17encoderpkt == 1)
|
||||
{
|
||||
//disable RRC filter for now
|
||||
opts.use_cosine_filter = 0;
|
||||
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
encodeM17PKT(&opts, &state);
|
||||
}
|
||||
|
||||
else if (opts.m17decoderip == 1)
|
||||
{
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
//open any outputs, if not already opened
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
processM17IPF(&opts, &state);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
350
src/dsd_mbe.c
350
src/dsd_mbe.c
@@ -18,8 +18,6 @@
|
||||
#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
|
||||
@@ -175,30 +173,6 @@ 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);
|
||||
@@ -474,7 +448,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->forced_alg_id == 1 && state->R > 0) )
|
||||
(state->M == 1 && state->R > 0) )
|
||||
{
|
||||
|
||||
if (state->payload_miN == 0)
|
||||
@@ -582,7 +556,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->forced_alg_id == 0 && state->payload_algid == 0)
|
||||
if (state->M == 0 && state->payload_algid == 0)
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
hash = state->lasttg & 0xFFFFFF;
|
||||
@@ -608,7 +582,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->forced_alg_id == 1) )
|
||||
(state->K > 0 && state->M == 1) )
|
||||
{
|
||||
k = BPK[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
@@ -620,7 +594,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->forced_alg_id == 1) )
|
||||
(state->K1 > 0 && state->M == 1) )
|
||||
{
|
||||
|
||||
int pos = 0;
|
||||
@@ -738,8 +712,6 @@ 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
|
||||
{
|
||||
|
||||
@@ -774,16 +746,6 @@ 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
|
||||
@@ -797,17 +759,18 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
//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++)
|
||||
{
|
||||
for (i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= state->ks_bitstreamL[state->bit_counterL++];
|
||||
for (j = 0; j < 8; j++)
|
||||
ambe_d[z++] ^= 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;
|
||||
@@ -845,24 +808,15 @@ 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));
|
||||
|
||||
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));
|
||||
state->dropL += 7;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
@@ -903,115 +857,49 @@ 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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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)
|
||||
//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)
|
||||
{
|
||||
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!
|
||||
}
|
||||
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)
|
||||
{
|
||||
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!
|
||||
}
|
||||
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)
|
||||
{
|
||||
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!
|
||||
}
|
||||
//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,
|
||||
@@ -1044,7 +932,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->forced_alg_id == 0 && state->payload_algidR == 0)
|
||||
if (state->M == 0 && state->payload_algidR == 0)
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
hash = state->lasttgR & 0xFFFFFF;
|
||||
@@ -1070,7 +958,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->forced_alg_id == 1) )
|
||||
(state->K > 0 && state->M == 1) )
|
||||
{
|
||||
k = BPK[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
@@ -1082,7 +970,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->forced_alg_id == 1))
|
||||
(state->K1 > 0 && state->M == 1))
|
||||
{
|
||||
|
||||
int pos = 0;
|
||||
@@ -1200,8 +1088,6 @@ 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
|
||||
{
|
||||
|
||||
@@ -1236,16 +1122,6 @@ 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
|
||||
@@ -1259,17 +1135,18 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
//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++)
|
||||
{
|
||||
for (i = 0; i < 49; i++)
|
||||
ambe_d[i] ^= state->ks_bitstreamR[state->bit_counterR++];
|
||||
for (j = 0; j < 8; j++)
|
||||
ambe_d[z++] ^= 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;
|
||||
@@ -1307,22 +1184,14 @@ 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 (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;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -1364,115 +1233,48 @@ 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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
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 TYT EP, Either Slot (static single key'd enforced KS)
|
||||
if (state->tyt_ep == 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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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!
|
||||
}
|
||||
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)
|
||||
{
|
||||
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!
|
||||
}
|
||||
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)
|
||||
{
|
||||
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!
|
||||
}
|
||||
//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,
|
||||
|
||||
145
src/dsd_misc.c
145
src/dsd_misc.c
@@ -593,129 +593,26 @@ long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as
|
||||
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).
|
||||
/*
|
||||
* Mean power (RMS^2 proxy) without sqrt, modeled after mean_power() in rtl_sdr_fm.cpp.
|
||||
* Computes a DC-corrected average of squares to avoid costly sqrt operations.
|
||||
*/
|
||||
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD])
|
||||
long int raw_pwr(int16_t *samples, int len, int step)
|
||||
{
|
||||
|
||||
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]];
|
||||
}
|
||||
int64_t p = 0;
|
||||
int64_t t = 0;
|
||||
for (int i = 0; i < len; i += step) {
|
||||
int64_t s = (int64_t)samples[i];
|
||||
t += s;
|
||||
p += s * s;
|
||||
}
|
||||
/* DC-corrected energy ≈ p - (t^2)/len with rounded division */
|
||||
int64_t dc_corr = 0;
|
||||
if (len > 0) {
|
||||
int64_t tt = t * t;
|
||||
dc_corr = (tt + (len / 2)) / len;
|
||||
}
|
||||
int64_t energy = p - dc_corr;
|
||||
if (energy < 0) energy = 0;
|
||||
return (long int)(energy / (len > 0 ? len : 1));
|
||||
}
|
||||
@@ -34,7 +34,10 @@ 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
|
||||
ncursesMenu (opts, state);
|
||||
{
|
||||
if (opts->m17encoder == 0) //don't allow menu if using M17 encoder
|
||||
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
|
||||
@@ -211,14 +214,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->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
|
||||
else state->forced_alg_id = 1;
|
||||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||||
else state->M = 1;
|
||||
}
|
||||
|
||||
if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry
|
||||
{
|
||||
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
|
||||
else state->forced_alg_id = 0x21;
|
||||
if (state->M == 1 || state->M == 0x21) state->M = 0;
|
||||
else state->M = 0x21;
|
||||
}
|
||||
|
||||
if (c == 105) //'i' key, toggle signal inversion on inverted types
|
||||
@@ -230,6 +233,7 @@ 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
|
||||
{
|
||||
@@ -237,6 +241,7 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,6 +888,16 @@ 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;
|
||||
|
||||
@@ -130,13 +130,11 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
closePulseOutput (opts);
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
//close OSS output
|
||||
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
|
||||
{
|
||||
close (opts->audio_out_fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opts->audio_in_type == 0) //close pulse input if it is the specified input method
|
||||
{
|
||||
@@ -419,7 +417,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
entry_win = newwin(8, WIDTH+22, starty+10, startx+10);
|
||||
box (entry_win, 0, 0);
|
||||
mvwprintw(entry_win, 2, 2, " RTL RMS Squelch Level (NXDN/dPMR/Analog/Raw only): ");
|
||||
mvwprintw(entry_win, 2, 2, " RTL Power Squelch Level (NXDN/dPMR/Analog/Raw only): ");
|
||||
mvwprintw(entry_win, 3, 3, " ");
|
||||
echo();
|
||||
refresh();
|
||||
@@ -465,7 +463,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
mvwprintw(entry_win, 8, 2, " RTL Volume Multiplier: %d", opts->rtl_volume_multiplier);
|
||||
mvwprintw(entry_win, 9, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port);
|
||||
mvwprintw(entry_win, 10, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error);
|
||||
mvwprintw(entry_win, 11, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level);
|
||||
mvwprintw(entry_win, 11, 2, " RTL PWR Squelch: %d", opts->rtl_squelch_level);
|
||||
mvwprintw(entry_win, 13, 2, " Are You Sure?");
|
||||
mvwprintw(entry_win, 14, 2, " 1 = Yes, 2 = No ");
|
||||
mvwprintw(entry_win, 15, 3, " ");
|
||||
@@ -923,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->forced_alg_id == 1 || state->forced_alg_id == 0x21)
|
||||
if (state->M == 1 || state->M == 0x21)
|
||||
{
|
||||
state->forced_alg_id = 0;
|
||||
state->M = 0;
|
||||
}
|
||||
else state->forced_alg_id = 1;
|
||||
else state->M = 1;
|
||||
}
|
||||
|
||||
if (option == 5)
|
||||
@@ -953,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->forced_alg_id == 1 || state->forced_alg_id == 0x21)
|
||||
// if (state->M == 1 || state->M == 0x21)
|
||||
// {
|
||||
// state->forced_alg_id = 0;
|
||||
// state->M = 0;
|
||||
// }
|
||||
// else state->forced_alg_id = 0x21;
|
||||
// else state->M = 0x21;
|
||||
// }
|
||||
|
||||
//load AES keys
|
||||
@@ -1417,6 +1415,7 @@ 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
|
||||
{
|
||||
@@ -1424,6 +1423,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->inverted_x2tdma = 0;
|
||||
opts->inverted_ysf = 0;
|
||||
opts->inverted_m17 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1587,12 +1587,10 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
openPulseOutput (opts);
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
|
||||
{
|
||||
openOSSOutput (opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method
|
||||
|
||||
@@ -223,6 +223,9 @@ 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);
|
||||
@@ -252,7 +255,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw (" V: %iX;", opts->rtl_volume_multiplier);
|
||||
printw (" PPM: %i;", opts->rtlsdr_ppm_error); //Adjust manually now with { and }
|
||||
printw (" SQ: %i;", opts->rtl_squelch_level);
|
||||
printw (" RMS: %04li;", opts->rtl_rms);
|
||||
printw (" PWR: %04li;", opts->rtl_pwr);
|
||||
printw (" BW: %i;", opts->rtl_bandwidth);
|
||||
printw (" FRQ: %i;", opts->rtlsdr_center_freq);
|
||||
if (opts->rtl_udp_port != 0) printw ("\n| External RTL Tuning on UDP Port: %i", opts->rtl_udp_port);
|
||||
@@ -279,7 +282,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("| Pulse Analog Output: %i kHz; %i Ch; G: %02.0f%% (/|*) ", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->audio_gainA);
|
||||
if (opts->audio_gainA == 0.0f) printw ("Auto ");
|
||||
else printw ("Manual ");
|
||||
if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms);
|
||||
if (opts->audio_in_type != 3) printw ("PWR: %04ld; ", opts->rtl_pwr);
|
||||
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 (" |");
|
||||
@@ -299,7 +302,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||||
{
|
||||
printw ("\n| Analog Monitor RMS: %04ld; G: %02.0f%% (/|*) ", opts->rtl_rms, opts->audio_gainA);
|
||||
printw ("\n| Analog Monitor PWR: %04ld; G: %02.0f%% (/|*) ", opts->rtl_pwr, opts->audio_gainA);
|
||||
if (opts->audio_gainA == 0.0f) printw ("Auto ");
|
||||
else printw ("Manual ");
|
||||
if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |");
|
||||
@@ -318,14 +321,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->use_hpf_d == 1) printw (" HPF");
|
||||
if (opts->call_alert == 1) printw (" *CA!"); //Call Alert
|
||||
if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||||
printw (" - Monitor RMS: %04ld ", opts->rtl_rms);
|
||||
printw (" - Monitor PWR: %04ld ", opts->rtl_pwr);
|
||||
printw (" \n");
|
||||
if (opts->udp_sockfdA != 0) //Analog Output on udp port +2
|
||||
{
|
||||
printw ("| UDP Analog Output: %s:%d; 48 kHz 1 Ch; G: %02.0f%% (/|*) ", opts->udp_hostname, opts->udp_portno+2, opts->audio_gainA);
|
||||
if (opts->audio_gainA == 0.0f) printw ("A ");
|
||||
else printw ("M ");
|
||||
if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms);
|
||||
if (opts->audio_in_type != 3) printw ("PWR: %04ld; ", opts->rtl_pwr);
|
||||
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 (" |");
|
||||
@@ -333,6 +336,25 @@ 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_pwr, 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);
|
||||
@@ -495,18 +517,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
#endif
|
||||
// if (opts->aggressive_framesync == 0) printw ("| Selective CRC ERR Bypass Enabled (RAS) \n");
|
||||
if (state->forced_alg_id == 1)
|
||||
if (state->M == 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->forced_alg_id == 0x21)
|
||||
if (state->M == 0x21)
|
||||
{
|
||||
if (state->R != 0) printw ("| Forcing Key Priority -- RC4 Key: %010llX \n", state->R);
|
||||
}
|
||||
if (state->forced_alg_id == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
|
||||
if (state->M == 0x16) printw ("| Forcing Key Priority -- TYT 16-bit Key: %04llX \n", state->H);
|
||||
|
||||
if (opts->scanner_mode == 1)
|
||||
{
|
||||
@@ -539,6 +561,7 @@ 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
|
||||
@@ -631,22 +654,20 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("\n");
|
||||
printw ("| ");
|
||||
|
||||
|
||||
//fill in any extra info, like Meta (IV, etc)
|
||||
if (state->m17_enc == 1)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("Scrambler - Type: %d", state->m17_enc_st);
|
||||
attron(COLOR_PAIR(3));
|
||||
printw (" Scrambler - Type: %d", state->m17_enc_st);
|
||||
}
|
||||
|
||||
if (state->m17_enc == 2)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("AES-CTR IV: ");
|
||||
//display AES IV
|
||||
printw ("AES-CTR - IV: ");
|
||||
//display packed meta as IV
|
||||
for (i = 0; i < 16; i++)
|
||||
printw ("%02X", state->m17_aes_iv[i]);
|
||||
attron(COLOR_PAIR(3));
|
||||
printw ("%02X", state->m17_meta[i]);
|
||||
}
|
||||
|
||||
if (state->m17_enc == 3)
|
||||
@@ -655,30 +676,6 @@ 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");
|
||||
|
||||
}
|
||||
|
||||
@@ -1112,26 +1109,6 @@ 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");
|
||||
|
||||
@@ -1307,26 +1284,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw(" Key: %010llX", state->RR);
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algidR == 0x36)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Advanced ");
|
||||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algidR == 0x37)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Universal ");
|
||||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->payload_algidR == 0x35)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw("Kirisun Encryption "); //0x35 is a placeholder if gained through late-entry method and alg is not known
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
printw ("\n");
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ void error(char *msg) {
|
||||
|
||||
struct sockaddr_in address;
|
||||
struct sockaddr_in addressA;
|
||||
struct sockaddr_in addressM17;
|
||||
|
||||
//
|
||||
// Connect
|
||||
@@ -323,6 +324,18 @@ 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)
|
||||
{
|
||||
@@ -340,6 +353,20 @@ 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);
|
||||
@@ -420,6 +447,46 @@ 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
|
||||
|
||||
@@ -132,7 +132,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
if (get_rtlsdr_sample(&sample, opts, state) < 0)
|
||||
cleanupAndExit(opts, state);
|
||||
//update root means square power level
|
||||
opts->rtl_rms = rtl_return_rms();
|
||||
opts->rtl_pwr = rtl_return_pwr();
|
||||
sample *= opts->rtl_volume_multiplier;
|
||||
|
||||
#endif
|
||||
@@ -268,9 +268,9 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
|
||||
if (state->analog_sample_counter == 960)
|
||||
{
|
||||
//get an rms value if not using the rtl built in version
|
||||
//get an pwr value if not using the rtl built in version
|
||||
if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
|
||||
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||
opts->rtl_pwr = raw_pwr(state->analog_out, 960, 1);
|
||||
|
||||
//raw wav file saving -- only write when not NXDN, dPMR, or M17 due to noise that can cause tons of false positives when no sync
|
||||
if (opts->wav_out_raw != NULL && opts->frame_nxdn48 == 0 && opts->frame_nxdn96 == 0 && opts->frame_dpmr == 0 && opts->frame_m17 == 0)
|
||||
@@ -299,13 +299,13 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
else
|
||||
agsm(opts, state, state->analog_out, 960);
|
||||
|
||||
//Running RMS after filtering does remove the analog spike from the RMS value
|
||||
//Running PWR after filtering does remove the analog spike from the PWR value
|
||||
//but noise floor noise will still produce higher values
|
||||
// if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
|
||||
// opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||
// opts->rtl_pwr = raw_pwr(state->analog_out, 960, 1);
|
||||
|
||||
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
|
||||
if ( (opts->rtl_rms > opts->rtl_squelch_level) && opts->monitor_input_audio == 1 && state->carrier == 0 ) //added carrier check here in lieu of disabling it above
|
||||
//seems to be working now, but PWR values are lower on actual analog signal than on no signal but noise
|
||||
if ( (opts->rtl_pwr > opts->rtl_squelch_level) && opts->monitor_input_audio == 1 && state->carrier == 0 ) //added carrier check here in lieu of disabling it above
|
||||
{
|
||||
if (opts->audio_out_type == 0)
|
||||
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
||||
|
||||
@@ -179,7 +179,7 @@ unsigned long long int edacsVoteFr(unsigned long long int fr_1_4, unsigned long
|
||||
void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn)
|
||||
{
|
||||
int i, result;
|
||||
int count = 5; //RMS has a 5 count (5 * 180ms) now before cutting off;
|
||||
int count = 5; //PWR has a 5 count (5 * 180ms) now before cutting off;
|
||||
short analog1[960];
|
||||
short analog2[960];
|
||||
short analog3[960];
|
||||
@@ -202,7 +202,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
|
||||
memset (d2, 0, sizeof(d2));
|
||||
memset (d3, 0, sizeof(d3));
|
||||
|
||||
long int rms = opts->rtl_squelch_level + 1; //one more for the initial loop phase
|
||||
long int pwr = opts->rtl_squelch_level + 1; //one more for the initial loop phase
|
||||
long int sql = opts->rtl_squelch_level;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
@@ -229,8 +229,8 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
analog3[i] = sample;
|
||||
}
|
||||
//this rms will only work properly (for now) with squelch enabled in SDR++ or other
|
||||
rms = raw_rms(analog3, 960, 1);
|
||||
//this pwr will only work properly (for now) with squelch enabled in SDR++ or other
|
||||
pwr = raw_pwr(analog3, 960, 1);
|
||||
}
|
||||
|
||||
//NOTE: The core dumps observed previously were due to SDR++ Remote Server connection dropping due to Internet/Other issues
|
||||
@@ -287,8 +287,8 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
|
||||
analog3[i] = sample;
|
||||
}
|
||||
|
||||
//this rms will only work properly (for now) with squelch enabled in SDR++
|
||||
rms = raw_rms(analog3, 960, 1);
|
||||
//this pwr will only work properly (for now) with squelch enabled in SDR++
|
||||
pwr = raw_pwr(analog3, 960, 1);
|
||||
}
|
||||
|
||||
//RTL Input
|
||||
@@ -315,8 +315,8 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
|
||||
sample *= opts->rtl_volume_multiplier;
|
||||
analog3[i] = sample;
|
||||
}
|
||||
//the rtl rms value works properly without needing a 'hard' squelch value
|
||||
rms = rtl_return_rms();
|
||||
//the rtl pwr value works properly without needing a 'hard' squelch value
|
||||
pwr = rtl_return_pwr();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -387,12 +387,12 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
|
||||
agsm (opts, state, analog3, 960);
|
||||
}
|
||||
|
||||
//NOTE: Ideally, we would run raw_rms for TCP/VS here, but the analog spike on EDACS (STM)
|
||||
//NOTE: Ideally, we would run raw_pwr for TCP/VS here, but the analog spike on EDACS (STM)
|
||||
//system gets filtered out, and when they hold the radio open and don't talk,
|
||||
//it counts against the squelch hit as no audio, so we will just have to use
|
||||
//the squelch checkbox in SDR++ and similar when using those input methods
|
||||
// if (opts->audio_in_type != 3)
|
||||
// rms = raw_rms(analog3, 960, 1);
|
||||
// pwr = raw_pwr(analog3, 960, 1);
|
||||
|
||||
//reconfigured to use seperate audio out stream that is always 48k short
|
||||
if (opts->audio_out_type == 0 && opts->slot1_on == 1)
|
||||
@@ -425,18 +425,18 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn
|
||||
write (opts->audio_out_fd, analog3, 960*2);
|
||||
}
|
||||
|
||||
opts->rtl_rms = rms;
|
||||
opts->rtl_pwr = pwr;
|
||||
|
||||
|
||||
printFrameSync (opts, state, " EDACS", 0, "A");
|
||||
|
||||
if (rms < sql) count--;
|
||||
if (pwr < sql) count--;
|
||||
else count = 5;
|
||||
|
||||
if (rms > sql) fprintf(stderr, "%s", KGRN);
|
||||
if (pwr > sql) fprintf(stderr, "%s", KGRN);
|
||||
else fprintf(stderr, "%s", KRED);
|
||||
|
||||
fprintf (stderr, " Analog RMS: %04ld SQL: %ld", rms, sql);
|
||||
fprintf (stderr, " Analog PWR: %04ld SQL: %ld", pwr, sql);
|
||||
if (state->ea_mode == 0)
|
||||
{
|
||||
int a = (afs >> state->edacs_a_shift) & state->edacs_a_mask;
|
||||
@@ -1488,7 +1488,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
//signal level drops (PWR, or a dotting sequence is detected)
|
||||
|
||||
//this is working now with the new import setup
|
||||
if (opts->trunk_tune_group_calls == 1 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
@@ -1743,7 +1743,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
//signal level drops (PWR, or a dotting sequence is detected)
|
||||
|
||||
//this is working now with the new import setup
|
||||
if (((is_individual == 0 && opts->trunk_tune_group_calls == 1) || (is_individual == 1 && opts->trunk_tune_private_calls == 1)) &&
|
||||
@@ -1857,7 +1857,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
//signal level drops (PWR, or a dotting sequence is detected)
|
||||
|
||||
//this is working now with the new import setup
|
||||
if ((opts->trunk_tune_private_calls == 1) && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
@@ -2153,7 +2153,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
//signal level drops (PWR, or a dotting sequence is detected)
|
||||
|
||||
//this is working now with the new import setup
|
||||
if ((opts->trunk_tune_group_calls == 1) && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
@@ -2299,10 +2299,6 @@ void eot_cc(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
fprintf (stderr, "EOT; \n");
|
||||
|
||||
//skip an arbitrary number of dibits so that the CC can cancel the grant after a dotting sequence
|
||||
//prior to returning to the control channel and getting sent in a loopback to the call channel
|
||||
skipDibit(opts, state, 240*8);
|
||||
|
||||
//watchdog event at this point
|
||||
state->lastsynctype = 38;
|
||||
watchdog_event_history(opts, state, 0);
|
||||
|
||||
@@ -25,45 +25,26 @@
|
||||
#include "dsd.h"
|
||||
#include "nxdn_const.h"
|
||||
|
||||
void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len)
|
||||
//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)
|
||||
{
|
||||
|
||||
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++)
|
||||
for (int i=0; i<len; i++)
|
||||
{
|
||||
//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);
|
||||
|
||||
if (scramble_t[i] >= len)
|
||||
break;
|
||||
dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits
|
||||
}
|
||||
|
||||
//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])
|
||||
@@ -123,11 +104,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, 80);
|
||||
crc = crc12f (trellis_buf, 84); //80
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[80+i];
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
}
|
||||
|
||||
//debug
|
||||
@@ -146,11 +127,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, 80);
|
||||
crc = crc12f (trellis_buf, 84);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+80];
|
||||
check = check | trellis_buf[i+84];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +284,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->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->M == 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);
|
||||
@@ -361,7 +342,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->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
|
||||
// if (crc != check)
|
||||
@@ -378,13 +359,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->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->M == 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->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->M == 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;
|
||||
@@ -582,15 +563,12 @@ 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->forced_alg_id == 1)
|
||||
if (sf_fb && state->M == 1)
|
||||
state->payload_miN = 0;
|
||||
|
||||
//currently using static values so event log will log something, and do wav files, etc
|
||||
@@ -601,10 +579,8 @@ 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;
|
||||
|
||||
//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");
|
||||
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)
|
||||
@@ -676,18 +652,12 @@ 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], uint8_t lich)
|
||||
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
{
|
||||
uint8_t deperm[144]; //144
|
||||
uint8_t depunc[192]; //192
|
||||
@@ -744,11 +714,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, 80);
|
||||
crc = crc12f (trellis_buf, 84); //80
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[80+i];
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
}
|
||||
|
||||
//debug
|
||||
@@ -767,11 +737,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, 80);
|
||||
crc = crc12f (trellis_buf, 84);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+80];
|
||||
check = check | trellis_buf[i+84];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,72 +754,33 @@ 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);
|
||||
|
||||
//SB0 with CSM
|
||||
if (lich == 0x08)
|
||||
//may only be relevant on MFID 0x30 "F.R.C." Radios
|
||||
if (opcode == 0x0F)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
|
||||
//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);
|
||||
}
|
||||
//anything else
|
||||
else
|
||||
|
||||
//may only be relevant on MFID 0x30 "F.R.C." Radios
|
||||
if (opcode == 0x32)
|
||||
{
|
||||
|
||||
//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);
|
||||
|
||||
}
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -863,18 +794,14 @@ void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144],
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
if (lich == 0x08)
|
||||
fprintf (stderr, "PICH (CRC ERR)");
|
||||
else fprintf (stderr, "TCH (CRC ERR)");
|
||||
fprintf (stderr, "TCH (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
if (lich == 0x08)
|
||||
fprintf (stderr, " PICH Payload ");
|
||||
else fprintf (stderr, " TCH Payload ");
|
||||
fprintf (stderr, " TCH Payload ");
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
@@ -1355,7 +1282,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 < 7; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+25];
|
||||
@@ -1377,7 +1304,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->forced_alg_id == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1489,11 +1416,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, 80);
|
||||
crc[j] = crc12f (trellis_buf, 84); //84
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check[j] = check[j] << 1;
|
||||
check[j] = check[j] | trellis_buf[80+i];
|
||||
check[j] = check[j] | trellis_buf[84+i]; //84
|
||||
|
||||
}
|
||||
|
||||
@@ -1513,11 +1440,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, 80);
|
||||
crc[j] = crc12f (trellis_buf, 84);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check[j] = check[j] << 1;
|
||||
check[j] = check[j] | trellis_buf[i+80];
|
||||
check[j] = check[j] | trellis_buf[i+84];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1655,11 +1582,6 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
||||
else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA");
|
||||
else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP");
|
||||
else if (MessageType == 0x3F) fprintf(stderr, " ALIAS");
|
||||
//observed from #318 and found in ARIB STD-B54
|
||||
else if (MessageType == 0x21) fprintf(stderr, " VCALL_ARIB_STD_B54");
|
||||
else if (MessageType == 0x28) fprintf(stderr, " TX_REL_ARIB_STD_B54");
|
||||
else if (MessageType == 0x27) fprintf(stderr, " ALIAS_ARIB_STD_B54");
|
||||
//TODO: Add rest of ARIB STD-B54 Message Types (Also, need to add a flag F1 and F2 check here, or earlier and make a seperate one for this)
|
||||
else fprintf(stderr, " Unknown Message Type: %02X;", MessageType);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
|
||||
@@ -97,21 +97,6 @@ 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:
|
||||
|
||||
@@ -189,7 +174,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
if (state->forced_alg_id == 0)
|
||||
if (state->M == 0)
|
||||
state->nxdn_cipher_type = 0;
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
|
||||
@@ -207,7 +192,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
if (state->forced_alg_id == 0)
|
||||
if (state->M == 0)
|
||||
state->nxdn_cipher_type = 0;
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
#endif
|
||||
@@ -689,7 +674,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->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -737,7 +722,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->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1760,7 +1745,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->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -1779,7 +1764,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->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1874,335 +1859,6 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
|
||||
}
|
||||
|
||||
//ARIB STD-B54 Messages
|
||||
|
||||
//ARIB STD-B54 Page 22 - 選択呼出音声通信 and 選択呼出終話 (Selective Call Info and Call End)
|
||||
void NXDN_decode_VCALL_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
{
|
||||
|
||||
//MFID is the only difference, this is added, the rest are shifted 8 bits down
|
||||
uint8_t mfid = 0;
|
||||
uint8_t CCOption = 0;
|
||||
uint8_t CallType = 0;
|
||||
uint8_t VoiceCallOption = 0;
|
||||
uint16_t SourceUnitID = 0;
|
||||
uint16_t DestinationID = 0;
|
||||
uint8_t CipherType = 0;
|
||||
uint8_t KeyID = 0;
|
||||
uint8_t DuplexMode[32] = {0};
|
||||
uint8_t TransmissionMode[32] = {0};
|
||||
|
||||
uint8_t MessageType;
|
||||
/* Get the "Message Type" field */
|
||||
MessageType = (Message[2] & 1) << 5;
|
||||
MessageType |= (Message[3] & 1) << 4;
|
||||
MessageType |= (Message[4] & 1) << 3;
|
||||
MessageType |= (Message[5] & 1) << 2;
|
||||
MessageType |= (Message[6] & 1) << 1;
|
||||
MessageType |= (Message[7] & 1) << 0;
|
||||
|
||||
if (MessageType == 0x21) fprintf (stderr, "%s", KGRN); //VCALL
|
||||
else if (MessageType == 0x28) fprintf (stderr, "%s", KYEL); //TX_REL
|
||||
|
||||
mfid = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
|
||||
|
||||
/* Decode "CC Option" */
|
||||
CCOption = (uint8_t)ConvertBitIntoBytes(&Message[16], 8);
|
||||
state->NxdnElementsContent.CCOption = CCOption;
|
||||
|
||||
/* Decode "Call Type" */
|
||||
CallType = (uint8_t)ConvertBitIntoBytes(&Message[24], 3);
|
||||
state->NxdnElementsContent.CallType = CallType;
|
||||
|
||||
/* Decode "Voice Call Option" */
|
||||
VoiceCallOption = (uint8_t)ConvertBitIntoBytes(&Message[27], 5);
|
||||
state->NxdnElementsContent.VoiceCallOption = VoiceCallOption;
|
||||
|
||||
/* Decode "Source Unit ID" */
|
||||
SourceUnitID = (uint16_t)ConvertBitIntoBytes(&Message[32], 16);
|
||||
state->NxdnElementsContent.SourceUnitID = SourceUnitID;
|
||||
|
||||
/* Decode "Destination ID" */
|
||||
DestinationID = (uint16_t)ConvertBitIntoBytes(&Message[48], 16);
|
||||
state->NxdnElementsContent.DestinationID = DestinationID;
|
||||
|
||||
/* Decode the "Cipher Type" */
|
||||
CipherType = (uint8_t)ConvertBitIntoBytes(&Message[64], 2);
|
||||
state->NxdnElementsContent.CipherType = CipherType;
|
||||
|
||||
/* Decode the "Key ID" */
|
||||
KeyID = (uint8_t)ConvertBitIntoBytes(&Message[66], 6);
|
||||
state->NxdnElementsContent.KeyID = KeyID;
|
||||
|
||||
fprintf (stderr, "\n MFID: %02X; ", mfid);
|
||||
|
||||
/* Print the "CC Option" */
|
||||
if(CCOption & 0x80) fprintf(stderr, "Emergency ");
|
||||
if(CCOption & 0x40) fprintf(stderr, "Visitor ");
|
||||
if(CCOption & 0x20) fprintf(stderr, "Priority Paging ");
|
||||
|
||||
//Call String for Per Call WAV File
|
||||
sprintf (state->call_string[0], "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
if (CCOption & 0x80) strcat (state->call_string[0], " Emergency");
|
||||
if (CipherType) strcat (state->call_string[0], " Enc");
|
||||
|
||||
if((CipherType == 2) || (CipherType == 3))
|
||||
{
|
||||
state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
|
||||
state->NxdnElementsContent.PartOfNextEncryptedFrame = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
|
||||
state->NxdnElementsContent.PartOfNextEncryptedFrame = 1;
|
||||
}
|
||||
|
||||
/* Print the "Call Type" */
|
||||
fprintf (stderr, "%s - ", NXDN_Call_Type_To_Str(CallType));
|
||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
|
||||
/* Print the "Voice Call Option" */
|
||||
if (MessageType == 0x21) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
||||
if (MessageType == 0x21) fprintf(stderr, "%s %s (%02X) - ", DuplexMode, TransmissionMode, VoiceCallOption);
|
||||
else if (MessageType == 0x28) fprintf (stderr, " Transmission Release - "); //TX_REL
|
||||
|
||||
/* Print Source ID and Destination ID (Talk Group or Unit ID) */
|
||||
fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//if using the keyloader, then check for a key value first by the key id,
|
||||
//and then if not available, check by the destination (TG) id value
|
||||
//also, for DES and AES, set the nxdn_key varialbe to the DestID for IV and KS gen
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
//if Scrambler Key (and not running NXDN96 since that has VCALL in the non-voice frames)
|
||||
//NOTE: The scrambler seed carries on the state->R variable so that will reset incorrectly on NXDN96
|
||||
//NOTE: Observed on system with scrambler and AES keys on same TG, disabling loading DES and AES key by DestID
|
||||
if (CipherType == 1 && opts->frame_nxdn48 == 1 && opts->frame_nxdn96 == 0)
|
||||
{
|
||||
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
|
||||
else if (state->rkey_array[DestinationID] != 0) state->R = state->rkey_array[DestinationID];
|
||||
}
|
||||
|
||||
//if DES Key
|
||||
else if (CipherType == 2)
|
||||
{
|
||||
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
|
||||
// else if (state->rkey_array[DestinationID] != 0)
|
||||
// {
|
||||
// state->R = state->rkey_array[DestinationID];
|
||||
// state->nxdn_key = DestinationID;
|
||||
// }
|
||||
}
|
||||
|
||||
//if AES Key
|
||||
else if (CipherType == 3)
|
||||
{
|
||||
uint32_t kidx = 0;
|
||||
if (state->rkey_array[KeyID] != 0) kidx = KeyID;
|
||||
// else if (state->rkey_array[DestinationID] != 0)
|
||||
// {
|
||||
// kidx = DestinationID;
|
||||
// state->nxdn_key = DestinationID;
|
||||
// }
|
||||
|
||||
state->A1[0] = state->rkey_array[kidx+0x000];
|
||||
state->A2[0] = state->rkey_array[kidx+0x101];
|
||||
state->A3[0] = state->rkey_array[kidx+0x201];
|
||||
state->A4[0] = state->rkey_array[kidx+0x301];
|
||||
|
||||
//check to see if there is a value loaded or not
|
||||
if (state->A1[0] == 0 && state->A2[0] == 0 && state->A3[0] == 0 && state->A4[0] == 0)
|
||||
state->aes_key_loaded[0] = 0;
|
||||
else state->aes_key_loaded[0] = 1;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
state->aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
|
||||
state->aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
|
||||
state->aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
|
||||
state->aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
|
||||
}
|
||||
|
||||
state->R = state->A1[0]; //display KS stub
|
||||
}
|
||||
|
||||
} //end state->keyloader == 1
|
||||
|
||||
/* Print the "Cipher Type" */
|
||||
if(CipherType != 0 && MessageType == 0x21)
|
||||
{
|
||||
fprintf (stderr, "\n %s", KYEL);
|
||||
fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType));
|
||||
}
|
||||
|
||||
/* Print the Key ID */
|
||||
if(CipherType != 0 && MessageType == 0x21)
|
||||
{
|
||||
fprintf(stderr, "Key ID %u - ", KeyID & 0xFF);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CipherType == 0x01 && state->R > 0) //scrambler key value
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, "Value: %05lld", state->R);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CipherType == 0x02 && state->R > 0) //DES key value
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, "Value: %016llX", state->R);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CipherType == 0x03 && state->R > 0) //AES key stub
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, "KS: %016llX", state->R);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//only grab if VCALL
|
||||
if(MessageType == 0x21)
|
||||
{
|
||||
//only assign rid if not spare and not reserved (happens on private calls, unsure of its significance)
|
||||
if ( (VoiceCallOption & 0xF) < 4) //ideally, only want 0, 1, 2, 3, or 4 (or 6, 7 on telephone calls)
|
||||
state->nxdn_last_rid = SourceUnitID;
|
||||
state->nxdn_last_tg = DestinationID;
|
||||
state->nxdn_key = KeyID;
|
||||
if (CallType == 0 || CallType == 1) //broadcast and group
|
||||
state->gi[0] = 0;
|
||||
else if (CallType == 4) //private
|
||||
state->gi[0] = 1;
|
||||
else state->gi[0] = -1; //unassigned on any other values
|
||||
state->nxdn_cipher_type = CipherType;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
state->gi[0] = -1;
|
||||
sprintf (state->generic_talker_alias[0], "%s", "");
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
}
|
||||
|
||||
//set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic
|
||||
if (state->nxdn_cipher_type != 0)
|
||||
{
|
||||
state->dmr_encL = 1;
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0 || state->R != 0)
|
||||
{
|
||||
state->dmr_encL = 0;
|
||||
}
|
||||
|
||||
} /* End NXDN_decode_VCALL_ARIB() */
|
||||
|
||||
void NXDN_decode_ALIAS_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
{
|
||||
|
||||
uint8_t mfid = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
|
||||
|
||||
//ARIB STD-B54 (p171-172) describes this as always having 3 segments
|
||||
//but this is also signalled, so perhaps it can be variable
|
||||
uint8_t seg_num = (uint8_t)ConvertBitIntoBytes(&Message[16], 4);
|
||||
uint8_t seg_len = (uint8_t)ConvertBitIntoBytes(&Message[20], 4);
|
||||
|
||||
uint8_t seg_bytes[12]; memset(seg_bytes, 0, sizeof(seg_bytes));
|
||||
|
||||
int seg_byte_num = 6;
|
||||
for (int i = 0; i < seg_byte_num; i++)
|
||||
seg_bytes[i] = (uint8_t)ConvertBitIntoBytes(&Message[(i*8)+24], 8);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n Multi Segment Alias %d/%d; ", seg_num, seg_len);
|
||||
for (int i = 0; i < seg_byte_num; i++)
|
||||
fprintf (stderr, "%02X", seg_bytes[i]);
|
||||
}
|
||||
else fprintf (stderr, " %d/%d; ", seg_num, seg_len);
|
||||
|
||||
//copy to PDU superframe
|
||||
memcpy(state->dmr_pdu_sf[0]+(seg_num-1)*seg_byte_num, seg_bytes, seg_byte_num*sizeof(uint8_t));
|
||||
|
||||
int len = seg_byte_num * seg_len;
|
||||
|
||||
//TODO: Do a CRC32 Check, currently relying on each SACCH frame CRC instead
|
||||
|
||||
//extract CRC32
|
||||
uint32_t crc_ext = (state->dmr_pdu_sf[0][len-4] << 24) | (state->dmr_pdu_sf[0][len-3] << 16) |
|
||||
(state->dmr_pdu_sf[0][len-2] << 8) | state->dmr_pdu_sf[0][len-1];
|
||||
|
||||
//remove CRC32 bytes
|
||||
if (len > 4)
|
||||
len -= 4;
|
||||
|
||||
if (seg_num == seg_len)
|
||||
{
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n Completed Alias Encoded: ");
|
||||
for (int i = 0; i < (seg_len*seg_byte_num); i++)
|
||||
fprintf (stderr, "%02X", state->dmr_pdu_sf[0][i]);
|
||||
}
|
||||
|
||||
//Alias String
|
||||
char alias[500]; memset(alias, 0, sizeof(alias));
|
||||
int ptr = 0; //pointer to position in alias buffer
|
||||
int k = 0; //pointer to position in completed message
|
||||
uint16_t sjis = 0; //SHIFT-JIS character
|
||||
uint8_t utf8 = 0; //UTF-8 Character
|
||||
uint32_t c16 = 0; //Unicode Character returned from sjis_char_to_unicode
|
||||
|
||||
//SHIFT-JIS to UNICODE Conversion
|
||||
setlocale(LC_ALL, ""); //needed when encoded alias contains Japanese (or probably any non-roman charset that isn't default on users terminal)
|
||||
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n MFID: %02X; Encoded Len: %d; CRC: %04X; Alias: ", mfid, len, crc_ext);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
|
||||
c16 = 0;
|
||||
utf8 = state->dmr_pdu_sf[0][k];
|
||||
sjis = (state->dmr_pdu_sf[0][k] << 8) | state->dmr_pdu_sf[0][k+1];
|
||||
|
||||
if (utf8 >= 0x20 && utf8 < 0x7F)
|
||||
{
|
||||
c16 = sjis_char_to_unicode(utf8);
|
||||
fprintf (stderr, "%lc", c16);
|
||||
k++;
|
||||
}
|
||||
else if (sjis != 0)
|
||||
{
|
||||
c16 = sjis_char_to_unicode(sjis);
|
||||
fprintf (stderr, "%lc", c16);
|
||||
k+=2;
|
||||
}
|
||||
else if (utf8 == 0 && sjis == 0)
|
||||
break;
|
||||
|
||||
//Encode Unicode to UTF-8 if not a pass-through ASCII control character or 0
|
||||
if (c16 >= 0x0020)
|
||||
ptr += utf8_encode(c16, alias+ptr);
|
||||
|
||||
}
|
||||
|
||||
//terminate string failsafe
|
||||
alias[ptr++] = 0x00;
|
||||
alias[ptr++] = 0x00;
|
||||
|
||||
sprintf (state->generic_talker_alias[0], "%s", alias);
|
||||
sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s; ", alias);
|
||||
|
||||
//reset PDU superframe afterwards
|
||||
memset(state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||
}
|
||||
|
||||
} /* End NXDN_decode_ALIAS_ARIB() */
|
||||
|
||||
char * NXDN_Call_Type_To_Str(uint8_t CallType)
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
//collect lich bits first, if they are good, then we can collect the rest of them
|
||||
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
|
||||
|
||||
nxdn_pn95_dibit_scrambler (state, lich_dibits, 8);
|
||||
nxdn_descramble (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 == 0x08 || lich == 0x4A || lich == 0x48 || lich == 0x46)
|
||||
if (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,13 +223,9 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
sacch2 = 1;
|
||||
break;
|
||||
|
||||
//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;
|
||||
//DCR Data or End Frame
|
||||
case 0x48:
|
||||
pich_tch = 3; //may be 1, or 2 TCH (observed possibly both)
|
||||
pich_tch = 3;
|
||||
case 0x4A:
|
||||
sacch2 = 1;
|
||||
break;
|
||||
@@ -347,7 +343,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
dbuf[i+8] = getDibit(opts, state);
|
||||
}
|
||||
|
||||
nxdn_pn95_dibit_scrambler (state, dbuf, 182);
|
||||
nxdn_descramble (dbuf, 182); //sizeof(dbuf)
|
||||
|
||||
//seperate our dbuf (dibit_buffer) into individual bit array
|
||||
for (int i = 0; i < 182; i++)
|
||||
@@ -469,7 +465,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->forced_alg_id == 1) state->nxdn_cipher_type = 0x1;
|
||||
if (state->R != 0 && state->M == 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
|
||||
@@ -525,7 +521,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->forced_alg_id == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
if (state->M == 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)
|
||||
{
|
||||
@@ -565,8 +561,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, lich);
|
||||
if (pich_tch & 2) nxdn_deperm_pich_tch(opts, state, facch_bits_b, lich);
|
||||
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);
|
||||
|
||||
//only run facch in second slot if its not equal to the first one
|
||||
//ideally, this would work better AFTER decoding/FEC
|
||||
@@ -584,7 +580,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->forced_alg_id == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
//process voice frame
|
||||
nxdn_voice (opts, state, voice, dbuf);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
|
||||
*/
|
||||
|
||||
//return 0 if channel value is 0 or 0xFFFF
|
||||
// if (channel == 0) return 0; //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 == 0) return 0;
|
||||
if (channel == 0xFFFF) return 0;
|
||||
|
||||
//Note: Base Frequency is calculated as (Base Frequency) x (0.000005 MHz) from the IDEN_UP message.
|
||||
|
||||
@@ -310,18 +310,6 @@ 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)
|
||||
|
||||
@@ -1,138 +1,17 @@
|
||||
// BCH decoder implementation from OP25 (Copyright 2010, KA1RBI, GPL license)
|
||||
#include "dsd.h"
|
||||
#include <itpp/itcomm.h>
|
||||
|
||||
#include <vector>
|
||||
typedef std::vector<bool> bit_vector;
|
||||
#include "p25p1_check_nid.h"
|
||||
|
||||
static const int bchGFexp[64] = {
|
||||
1, 2, 4, 8, 16, 32, 3, 6, 12, 24, 48, 35, 5, 10, 20, 40,
|
||||
19, 38, 15, 30, 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, 51, 37,
|
||||
9, 18, 36, 11, 22, 44, 27, 54, 47, 29, 58, 55, 45, 25, 50, 39,
|
||||
13, 26, 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, 57, 49, 33, 0
|
||||
};
|
||||
|
||||
static const int bchGFlog[64] = {
|
||||
-1, 0, 1, 6, 2, 12, 7, 26, 3, 32, 13, 35, 8, 48, 27, 18,
|
||||
4, 24, 33, 16, 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, 19, 56,
|
||||
5, 62, 25, 11, 34, 31, 17, 47, 15, 23, 53, 51, 37, 44, 55, 40,
|
||||
10, 61, 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, 20, 59, 57, 58
|
||||
};
|
||||
|
||||
int bchDec(bit_vector& Codeword)
|
||||
{
|
||||
int elp[24][22], S[23];
|
||||
int D[23], L[24], uLu[24];
|
||||
int locn[11], reg[12];
|
||||
int i, j, U, q, count;
|
||||
int SynError, CantDecode;
|
||||
using namespace itpp;
|
||||
|
||||
SynError = 0; CantDecode = 0;
|
||||
// Ideas taken from http://op25.osmocom.org/trac/wiki.png/browser/op25/gr-op25/lib/decoder_ff_impl.cc
|
||||
// See also p25_training_guide.pdf page 48.
|
||||
// See also tia-102-baaa-a-project_25-fdma-common_air_interface.pdf page 40.
|
||||
// BCH encoder/decoder implementation from IT++. GNU GPL 3 license.
|
||||
|
||||
for (i = 1; i <= 22; i++) {
|
||||
S[i] = 0;
|
||||
for (j = 0; j <= 62; j++) {
|
||||
if (Codeword[j]) {
|
||||
S[i] = S[i] ^ bchGFexp[(i * j) % 63];
|
||||
}
|
||||
}
|
||||
if (S[i]) { SynError = 1; }
|
||||
S[i] = bchGFlog[S[i]];
|
||||
}
|
||||
|
||||
if (SynError) { // if there are errors, try to correct them
|
||||
L[0] = 0; uLu[0] = -1; D[0] = 0; elp[0][0] = 0;
|
||||
L[1] = 0; uLu[1] = 0; D[1] = S[1]; elp[1][0] = 1;
|
||||
for (i = 1; i <= 21; i++) {
|
||||
elp[0][i] = -1; elp[1][i] = 0;
|
||||
}
|
||||
U = 0;
|
||||
|
||||
do {
|
||||
U = U + 1;
|
||||
if (D[U] == -1) {
|
||||
L[U + 1] = L[U];
|
||||
for (i = 0; i <= L[U]; i++) {
|
||||
elp[U + 1][i] = elp[U][i];
|
||||
elp[U][i] = bchGFlog[elp[U][i]];
|
||||
}
|
||||
} else {
|
||||
q = U - 1;
|
||||
while ((D[q] == -1) && (q > 0)) { q = q - 1; }
|
||||
if (q > 0) {
|
||||
j = q;
|
||||
do { j = j - 1; if ((D[j] != -1) && (uLu[q] < uLu[j])) { q = j; }
|
||||
} while (j > 0);
|
||||
}
|
||||
|
||||
if (L[U] > L[q] + U - q) {
|
||||
L[U + 1] = L[U];
|
||||
} else {
|
||||
L[U + 1] = L[q] + U - q;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 21; i++) {
|
||||
elp[U + 1][i] = 0;
|
||||
}
|
||||
for (i = 0; i <= L[q]; i++) {
|
||||
if (elp[q][i] != -1) {
|
||||
elp[U + 1][i + U - q] = bchGFexp[(D[U] + 63 - D[q] + elp[q][i]) % 63];
|
||||
}
|
||||
}
|
||||
for (i = 0; i <= L[U]; i++) {
|
||||
elp[U + 1][i] = elp[U + 1][i] ^ elp[U][i];
|
||||
elp[U][i] = bchGFlog[elp[U][i]];
|
||||
}
|
||||
}
|
||||
uLu[U + 1] = U - L[U + 1];
|
||||
|
||||
if (U < 22) {
|
||||
if (S[U + 1] != -1) { D[U + 1] = bchGFexp[S[U + 1]]; } else { D[U + 1] = 0; }
|
||||
for (i = 1; i <= L[U + 1]; i++) {
|
||||
if ((S[U + 1 - i] != -1) && (elp[U + 1][i] != 0)) {
|
||||
D[U + 1] = D[U + 1] ^ bchGFexp[(S[U + 1 - i] + bchGFlog[elp[U + 1][i]]) % 63];
|
||||
}
|
||||
}
|
||||
D[U + 1] = bchGFlog[D[U + 1]];
|
||||
}
|
||||
} while ((U < 22) && (L[U + 1] <= 11));
|
||||
|
||||
U = U + 1;
|
||||
if (L[U] <= 11) {
|
||||
for (i = 0; i <= L[U]; i++) {
|
||||
elp[U][i] = bchGFlog[elp[U][i]];
|
||||
}
|
||||
|
||||
for (i = 1; i <= L[U]; i++) {
|
||||
reg[i] = elp[U][i];
|
||||
}
|
||||
count = 0;
|
||||
for (i = 1; i <= 63; i++) {
|
||||
q = 1;
|
||||
for (j = 1; j <= L[U]; j++) {
|
||||
if (reg[j] != -1) {
|
||||
reg[j] = (reg[j] + j) % 63;
|
||||
q = q ^ bchGFexp[reg[j]];
|
||||
}
|
||||
}
|
||||
if (q == 0) {
|
||||
locn[count] = 63 - i;
|
||||
count = count + 1;
|
||||
}
|
||||
}
|
||||
if (count == L[U]) {
|
||||
for (i = 0; i <= L[U] - 1; i++) {
|
||||
Codeword[locn[i]] = Codeword[locn[i]] ^ 1;
|
||||
}
|
||||
CantDecode = count;
|
||||
} else {
|
||||
CantDecode = -1;
|
||||
}
|
||||
} else {
|
||||
CantDecode = -2;
|
||||
}
|
||||
}
|
||||
return CantDecode;
|
||||
}
|
||||
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
|
||||
|
||||
/**
|
||||
* Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes
|
||||
@@ -145,13 +24,13 @@ private:
|
||||
|
||||
unsigned char get_index(unsigned char x, unsigned char y)
|
||||
{
|
||||
return (x << 2) + y;
|
||||
return (x<<2) + y;
|
||||
}
|
||||
|
||||
public:
|
||||
ParityTable()
|
||||
{
|
||||
for (unsigned int i = 0; i < sizeof(table); i++) {
|
||||
for (unsigned int i=0; i<sizeof(table); i++) {
|
||||
table[i] = 0;
|
||||
}
|
||||
table[get_index(1,1)] = 1;
|
||||
@@ -160,8 +39,9 @@ public:
|
||||
|
||||
unsigned char get_value(unsigned char x, unsigned char y)
|
||||
{
|
||||
return table[get_index(x, y)];
|
||||
return table[get_index(x,y)];
|
||||
}
|
||||
|
||||
} parity_table;
|
||||
|
||||
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity)
|
||||
@@ -169,38 +49,31 @@ int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity
|
||||
int result;
|
||||
|
||||
// Fill up with the given input
|
||||
bit_vector codeword(63);
|
||||
for (unsigned int i = 0; i < 63; i++) {
|
||||
codeword[i] = bch_code[62-i];
|
||||
bvec input(63);
|
||||
for(unsigned int i=0; i<63; i++) {
|
||||
input[i] = bch_code[i];
|
||||
}
|
||||
|
||||
// Decode it
|
||||
int errors = bchDec(codeword);
|
||||
bool ok = (errors >= 0);
|
||||
bvec decoded, cw_isvalid;
|
||||
bool ok = bch.decode(input, decoded, cw_isvalid);
|
||||
|
||||
if (!ok) {
|
||||
// Decode failed
|
||||
// fprintf (stderr, "NID ERR: %d; ", errors);
|
||||
result = 0;
|
||||
} else {
|
||||
//reload the codeword back into correct bit order
|
||||
for (unsigned int i = 0; i < 63; i++) {
|
||||
bch_code[i] = codeword[62-i];
|
||||
}
|
||||
for (unsigned int i = 0; i < 63; i++) {
|
||||
codeword[i] = bch_code[i];
|
||||
}
|
||||
// Take the NAC from the decoded output. It's a 12 bit number starting from position 0.
|
||||
// Just convert the output from a binary sequence to an integer.
|
||||
int nac = 0;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
for (int i=0; i<12; i++) {
|
||||
nac <<= 1;
|
||||
nac |= (int)codeword[i];
|
||||
nac |= (int)decoded[i];
|
||||
}
|
||||
*new_nac = nac;
|
||||
|
||||
// Take the fixed DUID from the encoded output. 4 bit value starting at position 12.
|
||||
unsigned char new_duid_0 = (((int)codeword[12]) << 1) + ((int)codeword[13]);
|
||||
unsigned char new_duid_1 = (((int)codeword[14]) << 1) + ((int)codeword[15]);
|
||||
unsigned char new_duid_0 = (((int)decoded[12])<<1) + ((int)decoded[13]);
|
||||
unsigned char new_duid_1 = (((int)decoded[14])<<1) + ((int)decoded[15]);
|
||||
new_duid[0] = new_duid_0 + '0';
|
||||
new_duid[1] = new_duid_1 + '0';
|
||||
new_duid[2] = 0; // Null terminate
|
||||
@@ -209,12 +82,12 @@ int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity
|
||||
unsigned char expected_parity = parity_table.get_value(new_duid_0, new_duid_1);
|
||||
|
||||
if (expected_parity != parity) {
|
||||
// Parity mismatch – optional handling
|
||||
// fprintf(stderr, "Error in parity detected?\n");
|
||||
// Ignore, not sure what to do
|
||||
//fprintf (stderr, "Error in parity detected?");
|
||||
}
|
||||
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,18 +317,6 @@ 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)
|
||||
{
|
||||
@@ -358,18 +346,6 @@ 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
|
||||
@@ -784,18 +760,6 @@ 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)
|
||||
{
|
||||
@@ -821,19 +785,6 @@ 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
|
||||
|
||||
3538
src/rtl_sdr_fm.cpp
3538
src/rtl_sdr_fm.cpp
File diff suppressed because it is too large
Load Diff
1217
src/sjis_unicode.c
1217
src/sjis_unicode.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user