mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
39 Commits
20260715
...
audio_work
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34753963b8 | ||
|
|
544d576551 | ||
|
|
72f8c1aff7 | ||
|
|
bfa4891965 | ||
|
|
daa47069bf | ||
|
|
587181f4de | ||
|
|
eb8048f1d9 | ||
|
|
d8f9bd190b | ||
|
|
6880087afe | ||
|
|
6106a608e3 | ||
|
|
1aae6d34c9 | ||
|
|
be57b5149b | ||
|
|
3e221f29f5 | ||
|
|
4754f6a59b | ||
|
|
7027b145b8 | ||
|
|
f38b5976f3 | ||
|
|
5244c85774 | ||
|
|
4005c9b313 | ||
|
|
72b3e5efe4 | ||
|
|
a3a6fb999a | ||
|
|
37855b817b | ||
|
|
4fe32db7f5 | ||
|
|
6819f9010e | ||
|
|
719d9709e6 | ||
|
|
26e4a619f6 | ||
|
|
0838a7f7ba | ||
|
|
a6ea60b345 | ||
|
|
9232d66fcb | ||
|
|
15515158b5 | ||
|
|
fa4a332582 | ||
|
|
4139b19bfe | ||
|
|
cd5f0f4a8e | ||
|
|
fb3dc75c47 | ||
|
|
f2254f413a | ||
|
|
c97400a704 | ||
|
|
cc6711fe4d | ||
|
|
198f0eacb5 | ||
|
|
5e5c3c4555 | ||
|
|
272f17bfa3 |
@@ -134,6 +134,7 @@ FILE(GLOB HEADERS include/*.h include/*.hpp)
|
|||||||
|
|
||||||
if(NOT RTLSDR_FOUND)
|
if(NOT RTLSDR_FOUND)
|
||||||
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_fm.cpp)
|
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_fm.cpp)
|
||||||
|
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_tcp.c)
|
||||||
endif(NOT RTLSDR_FOUND)
|
endif(NOT RTLSDR_FOUND)
|
||||||
|
|
||||||
configure_file("src/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY)
|
configure_file("src/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
# Digital Speech Decoder - Florida Man Edition
|
# Digital Speech Decoder - Florida Man Edition
|
||||||
|
|
||||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and [Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and [Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP, ilyacodes, Phillipw1084 and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||||
|
|
||||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, ilyacodes, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,46 @@ LD_LIBRARY_PATH=/usr/local/lib
|
|||||||
export LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS Builds (Homebrew)
|
||||||
|
|
||||||
|
Building on macOS (Apple Silicon) using [Homebrew](https://brew.sh "Homebrew") for dependencies has been tested working, but keep in mind this project is primarily focused on Linux, so macOS support should be considered experimental. Unlike the Linux steps above, macOS has no `ldconfig`, so simply skip that step wherever it appears below.
|
||||||
|
|
||||||
|
Install dependencies first:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install cmake git libsndfile pulseaudio rtl-sdr codec2 ncurses pkg-config
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Homebrew's ncurses is keg-only (not symlinked into /opt/homebrew), so we will pass an extra CMake flag when configuring DSD-FME below so it can be found.
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
|
cd mbelib
|
||||||
|
git checkout ambe_tones
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j `sysctl -n hw.ncpu`
|
||||||
|
sudo make install
|
||||||
|
cd ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
Finish by cloning and building DSD-FME (note the added -DCMAKE_PREFIX_PATH flag for keg-only ncurses):
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
|
cd dsd-fme
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_PREFIX_PATH=$(brew --prefix ncurses)
|
||||||
|
make -j `sysctl -n hw.ncpu`
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Pulse Audio is still the default input/output in DSD-FME, so start the Homebrew Pulse Audio daemon before running dsd-fme (it will also restart at login): `brew services start pulseaudio`. To confirm your RTL-SDR dongle is detected, run `rtl_test` (ships with Homebrew's rtl-sdr package); unlike Linux, there is no driver blacklist to deal with on macOS.
|
||||||
|
|
||||||
### Windows Cygwin Builds
|
### Windows Cygwin Builds
|
||||||
|
|
||||||
Cygwin builds now have an experimental semi-automatic installer, to run, follow steps below:
|
Cygwin builds now have an experimental semi-automatic installer, to run, follow steps below:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Build Version: AW 2026-30-g43d63b2
|
Build Version: AW 2026-47-ga6ea60b
|
||||||
MBElib Version: 1.3.4
|
MBElib Version: 1.3.4
|
||||||
CODEC2 Support Enabled
|
CODEC2 Support Enabled
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@ Input/Output options:
|
|||||||
pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O)
|
pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O)
|
||||||
rtl for rtl dongle (Default Values -- see below)
|
rtl for rtl dongle (Default Values -- see below)
|
||||||
rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)
|
rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)
|
||||||
|
rtltcp:host:port:freq:gain:ppm:bw:sq:vol for rtl dongle on an rtl_tcp server (see below)
|
||||||
tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)
|
tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)
|
||||||
tcp:192.168.7.5:7355 for custom address and port
|
tcp:192.168.7.5:7355 for custom address and port
|
||||||
filename.bin for OP25/FME capture bin files
|
filename.bin for OP25/FME capture bin files
|
||||||
@@ -62,7 +63,6 @@ Input/Output options:
|
|||||||
-q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice
|
-q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice
|
||||||
-V <num> Enable TDMA Voice Synthesis on Slot 1 (1), Slot 2 (2), or Both (3); Default is 3;
|
-V <num> Enable TDMA Voice Synthesis on Slot 1 (1), Slot 2 (2), or Both (3); Default is 3;
|
||||||
-z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)
|
-z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)
|
||||||
-y Enable Experimental Pulse Audio Float Audio Output
|
|
||||||
-v <hex> Set Filtering Bitmap Options (Advanced Option)
|
-v <hex> Set Filtering Bitmap Options (Advanced Option)
|
||||||
1 1 1 1 (0xF): PBF/LPF/HPF/HPFD on
|
1 1 1 1 (0xF): PBF/LPF/HPF/HPFD on
|
||||||
|
|
||||||
@@ -78,6 +78,11 @@ RTL-SDR options:
|
|||||||
vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)
|
vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)
|
||||||
Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T
|
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
|
Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2
|
||||||
|
Usage: rtltcp:host:port:freq:gain:ppm:bw:sq:vol
|
||||||
|
host <name> rtl_tcp Server Hostname or IP Address (default = localhost)
|
||||||
|
port <num> rtl_tcp Server Port (default = 1234)
|
||||||
|
freq, gain, ppm, bw, sq, vol as above
|
||||||
|
Example: dsd-fme -fs -i rtltcp:192.168.1.10:1234:450M:26:-2:8 -C connect_plus_chan.csv -T
|
||||||
|
|
||||||
Decoder options:
|
Decoder options:
|
||||||
-fa Auto Detection
|
-fa Auto Detection
|
||||||
@@ -101,7 +106,6 @@ Decoder options:
|
|||||||
-fE Decode only EDACS EA/ProVoice with ESK 0xA0*
|
-fE Decode only EDACS EA/ProVoice with ESK 0xA0*
|
||||||
-fm Decode only dPMR*
|
-fm Decode only dPMR*
|
||||||
-l Disable DMR, dPMR, NXDN, M17 input filtering
|
-l Disable DMR, dPMR, NXDN, M17 input filtering
|
||||||
-u <num> Unvoiced speech quality (default=3)
|
|
||||||
-xx Expect non-inverted X2-TDMA signal
|
-xx Expect non-inverted X2-TDMA signal
|
||||||
-xr Expect inverted DMR signal
|
-xr Expect inverted DMR signal
|
||||||
-xd Expect inverted ICOM dPMR signal
|
-xd Expect inverted ICOM dPMR signal
|
||||||
@@ -138,11 +142,20 @@ Advanced Decoder options:
|
|||||||
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
-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, AES-256, or Kirisun 128 or 256 Hex Key (see example below)
|
||||||
Encapulate in Single Quotation Marks; Space every 16 chars.
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||||
|
|
||||||
|
-H <hex> Manually Enter Caltta 10/32/64 Char Basic Privacy Hex Key (see example below)
|
||||||
|
-H C:40:1234567890
|
||||||
|
-H C:128:736B9A9C5645288B243AD5CB8701EF8A'
|
||||||
|
-H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8'
|
||||||
|
|
||||||
|
-H <hex> Manually Enter Hytera OTA Encryption 32 Char Hex Key (see example below)
|
||||||
|
-H O:0:0 no keystream application, but check for Hytera OTA Encryption and DMRA EP Late Entry IV.
|
||||||
|
-H O:128:17bfe59b29a06136fb7d3811fd1a4904 for 128-bit RC4 OTA Key Setup
|
||||||
|
|
||||||
-R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)
|
-R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)
|
||||||
|
|
||||||
-1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value)
|
-1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value)
|
||||||
@@ -175,6 +188,23 @@ Advanced Decoder options:
|
|||||||
|
|
||||||
-A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value)
|
-A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value)
|
||||||
|
|
||||||
|
-$ <string> Enter RAS Password 6-24 Char Key Value (DMR) (a-z A-Z, 0-9, $ # _ -)
|
||||||
|
-$ Password123
|
||||||
|
|
||||||
|
Special Use Cases involving # and $, use parenthesis and put \ in front of all $ signs
|
||||||
|
-$ "######"
|
||||||
|
-$ "\$\$\$\$\$\$"
|
||||||
|
|
||||||
|
-y <hex> Enter RAS 56-bit Effective Key Value (DMR) (14 Char Hex Value)
|
||||||
|
-y 6DF241BC4AE2EC
|
||||||
|
|
||||||
|
-, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value)
|
||||||
|
-, Secure04
|
||||||
|
|
||||||
|
-u <string> Manually Enter Vertex Standard 10 or 64 Char Hex Key
|
||||||
|
-u 10:1234567891 or 64:AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD
|
||||||
|
-u 0:0 no KS application, but apply the inversion to the interleave (clear errors on 256)
|
||||||
|
|
||||||
-S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)
|
-S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)
|
||||||
For Example, enter 16-bit Keystream 0909 as:
|
For Example, enter 16-bit Keystream 0909 as:
|
||||||
-S 16:0909
|
-S 16:0909
|
||||||
@@ -184,6 +214,8 @@ Advanced Decoder options:
|
|||||||
-S 49:ED0AED4AED4AED4A
|
-S 49:ED0AED4AED4AED4A
|
||||||
For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:
|
For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:
|
||||||
-S 49:11AA22BB33CC44
|
-S 49:11AA22BB33CC44
|
||||||
|
For Example, Caltta 40-bit Keystream w/ optional 7-bit discard as:
|
||||||
|
-S 40:1234567890:7
|
||||||
|
|
||||||
-k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.
|
-k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.
|
||||||
Only supports NXDN, DMR Basic Privacy (decimal value).
|
Only supports NXDN, DMR Basic Privacy (decimal value).
|
||||||
@@ -214,7 +246,7 @@ Advanced Decoder options:
|
|||||||
-p Disable Tune to Private Calls (DMR TIII, P25, NXDN Type-C and Type-D)
|
-p Disable Tune to Private Calls (DMR TIII, P25, NXDN Type-C and Type-D)
|
||||||
-E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)
|
-E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)
|
||||||
-e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)
|
-e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)
|
||||||
(NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls
|
(NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls)
|
||||||
-I <dec> Specify TG to Hold During Trunking (DMR, P25, NXDN Type-C Trunking)
|
-I <dec> Specify TG to Hold During Trunking (DMR, P25, NXDN Type-C Trunking)
|
||||||
-U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)
|
-U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)
|
||||||
-B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)
|
-B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)
|
||||||
|
|||||||
@@ -22,27 +22,20 @@
|
|||||||
@REM set options to pass to dsd-fme
|
@REM set options to pass to dsd-fme
|
||||||
set "options= -N -Z "
|
set "options= -N -Z "
|
||||||
|
|
||||||
@REM Set Date Time for log (sourced from: https://stackoverflow.com/questions/1192476/format-date-and-time-in-a-windows-batch-script)
|
@REM Create Folder and Set Date Time for logs
|
||||||
@echo off
|
@echo off
|
||||||
REM "%date: =0%" replaces spaces with zeros
|
mkdir logs
|
||||||
set d=%date: =0%
|
@REM Locale-independent date/time for log filenames (yyyyMMdd_HHmmss)
|
||||||
REM "set yyyy=%d:~-4%" pulls the last 4 characters
|
@REM Works on older Windows without wmic or PowerShell
|
||||||
set yyyy=%d:~-4%
|
for /f "tokens=1-6 delims=/: " %%a in ('robocopy "|" . /njh ^| find ":"') do (
|
||||||
set mm=%d:~4,2%
|
set "YYYY=%%a"
|
||||||
set dd=%d:~7,2%
|
set "MM=%%b"
|
||||||
set dow=%d:~0,3%
|
set "DD=%%c"
|
||||||
set d=%yyyy%%mm%%dd%
|
set "HH=%%d"
|
||||||
|
set "Min=%%e"
|
||||||
set t=%TIME: =0%
|
set "Sec=%%f"
|
||||||
REM "%t::=%" removes semi-colons
|
)
|
||||||
REM Instead of above, you could use "%t::=-%" to
|
set "datetimestr=%YYYY%%MM%%DD%_%HH%%Min%%Sec%"
|
||||||
REM replace semi-colons with hyphens (or any
|
|
||||||
REM non-special character)
|
|
||||||
set t=%t::=%
|
|
||||||
set t=%t:.=%
|
|
||||||
|
|
||||||
set datetimestr=%d%_%t%
|
|
||||||
@REM @echo Long date time str = %datetimestr%
|
|
||||||
|
|
||||||
@REM random number is used so that two log files don't share the same name
|
@REM random number is used so that two log files don't share the same name
|
||||||
set rnd=%RANDOM%
|
set rnd=%RANDOM%
|
||||||
|
|||||||
@@ -372,6 +372,9 @@ typedef struct
|
|||||||
int rtl_bandwidth;
|
int rtl_bandwidth;
|
||||||
int rtl_started;
|
int rtl_started;
|
||||||
long int rtl_rms;
|
long int rtl_rms;
|
||||||
|
int rtltcp_enabled;
|
||||||
|
char rtltcp_hostname[1024];
|
||||||
|
int rtltcp_portno;
|
||||||
int monitor_input_audio;
|
int monitor_input_audio;
|
||||||
int analog_only;
|
int analog_only;
|
||||||
int pulse_raw_rate_in;
|
int pulse_raw_rate_in;
|
||||||
@@ -649,6 +652,14 @@ typedef struct
|
|||||||
//xl specific, we need to know if the ESS is from HDU, or from LDU2
|
//xl specific, we need to know if the ESS is from HDU, or from LDU2
|
||||||
int xl_is_hdu;
|
int xl_is_hdu;
|
||||||
|
|
||||||
|
//Vertex Standard Keys
|
||||||
|
// #define VERTEX_KEY40_BY_TG
|
||||||
|
// #define VERTEX_KEY256_BY_TG
|
||||||
|
char vtx256_key[64];
|
||||||
|
unsigned long long int vtx40_key;
|
||||||
|
unsigned long long int vtx256_ekey;
|
||||||
|
uint8_t vtx_key_loaded;
|
||||||
|
|
||||||
unsigned int debug_audio_errors;
|
unsigned int debug_audio_errors;
|
||||||
unsigned int debug_audio_errorsR;
|
unsigned int debug_audio_errorsR;
|
||||||
unsigned int debug_header_errors;
|
unsigned int debug_header_errors;
|
||||||
@@ -918,6 +929,26 @@ typedef struct
|
|||||||
//Remus DMR End Call Alert Beep
|
//Remus DMR End Call Alert Beep
|
||||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||||
|
|
||||||
|
//RAS Key Variables
|
||||||
|
// #define DEBUG_RAS
|
||||||
|
unsigned long long int ras_effective_key;
|
||||||
|
int ras_permutation_order[104];
|
||||||
|
uint8_t dmr_is_ras; //indicate a partial or complete RAS enabled system
|
||||||
|
|
||||||
|
//Hytera OTA Key Variables
|
||||||
|
// #define DEBUG_HOTA
|
||||||
|
uint8_t hota_enc_check;
|
||||||
|
uint8_t hota_key_loaded;
|
||||||
|
uint8_t dmr_is_hota;
|
||||||
|
int hota_bit_shift;
|
||||||
|
int hota_byte_shifts[12];
|
||||||
|
uint8_t hota_rc4_key[16];
|
||||||
|
uint8_t hota_rc4_ks[80];
|
||||||
|
uint8_t hota_lc_ctx[2][4];
|
||||||
|
uint8_t hota_ctx_ok[2];
|
||||||
|
int hota_sbrc_idx1[2];
|
||||||
|
int hota_sbrc_idx2[2];
|
||||||
|
|
||||||
//Bitmap Filtering Options
|
//Bitmap Filtering Options
|
||||||
int audio_smoothing;
|
int audio_smoothing;
|
||||||
|
|
||||||
@@ -1004,6 +1035,7 @@ typedef struct
|
|||||||
//generic ks
|
//generic ks
|
||||||
int straight_ks;
|
int straight_ks;
|
||||||
int straight_mod;
|
int straight_mod;
|
||||||
|
int straight_discard;
|
||||||
|
|
||||||
uint8_t static_ks_bits[2][882];
|
uint8_t static_ks_bits[2][882];
|
||||||
int static_ks_counter[2];
|
int static_ks_counter[2];
|
||||||
@@ -1200,7 +1232,6 @@ void printFrameInfo (dsd_opts * opts, dsd_state * state);
|
|||||||
void processFrame (dsd_opts * opts, dsd_state * state);
|
void processFrame (dsd_opts * opts, dsd_state * state);
|
||||||
void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation);
|
void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation);
|
||||||
int getFrameSync (dsd_opts * opts, dsd_state * state);
|
int getFrameSync (dsd_opts * opts, dsd_state * state);
|
||||||
int comp (const void *a, const void *b);
|
|
||||||
void noCarrier (dsd_opts * opts, dsd_state * state);
|
void noCarrier (dsd_opts * opts, dsd_state * state);
|
||||||
void initOpts (dsd_opts * opts);
|
void initOpts (dsd_opts * opts);
|
||||||
void initState (dsd_state * state);
|
void initState (dsd_state * state);
|
||||||
@@ -1358,11 +1389,14 @@ int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24]);
|
|||||||
|
|
||||||
//BPTC (Block Product Turbo Code) functions
|
//BPTC (Block Product Turbo Code) functions
|
||||||
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output);
|
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output);
|
||||||
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3]);
|
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3], uint8_t * is_ras);
|
||||||
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]);
|
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]);
|
||||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd);
|
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd);
|
||||||
|
uint32_t BPTC_128x77_Check_Errors(uint8_t InputDataMatrix[8][16]);
|
||||||
|
|
||||||
//Reed Solomon (12,9) functions
|
//Reed Solomon DMR functions
|
||||||
|
void rs_16_13_encode(uint8_t * input);
|
||||||
|
void rs_12_9_encode(uint8_t * input);
|
||||||
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome);
|
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome);
|
||||||
uint8_t rs_12_9_check_syndrome(rs_12_9_poly_t *syndrome);
|
uint8_t rs_12_9_check_syndrome(rs_12_9_poly_t *syndrome);
|
||||||
rs_12_9_correct_errors_result_t rs_12_9_correct_errors(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome, uint8_t *errors_found);
|
rs_12_9_correct_errors_result_t rs_12_9_correct_errors(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome, uint8_t *errors_found);
|
||||||
@@ -1375,6 +1409,7 @@ uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes,
|
|||||||
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
|
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
|
||||||
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
|
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
|
||||||
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData);
|
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData);
|
||||||
|
uint32_t ComputeCrc32BitV(uint8_t * DMRData, uint32_t NbData);
|
||||||
|
|
||||||
//new simplified dmr functions
|
//new simplified dmr functions
|
||||||
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
|
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
|
||||||
@@ -1496,6 +1531,11 @@ void LFSRP(dsd_state * state);
|
|||||||
void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state);
|
void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state);
|
||||||
void LFSR64(dsd_state * state);
|
void LFSR64(dsd_state * state);
|
||||||
|
|
||||||
|
//IV Reversals using LFSR tap +1 arrangements
|
||||||
|
uint64_t reverse_lfsr_32a_to_len(uint8_t * iv, int16_t len);
|
||||||
|
uint64_t reverse_lfsr_32d_to_len(uint8_t * iv, int16_t len);
|
||||||
|
uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len);
|
||||||
|
|
||||||
void Hamming_7_4_init();
|
void Hamming_7_4_init();
|
||||||
void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits);
|
void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||||
bool Hamming_7_4_decode(unsigned char *rxBits);
|
bool Hamming_7_4_decode(unsigned char *rxBits);
|
||||||
@@ -1638,7 +1678,7 @@ 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_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);
|
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 / Retevis / Anytone / Kenwood / Vertex / Baofeng / Misc DMR Encryption Modes
|
||||||
void tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int fnum);
|
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_ep_aes_keystream_creation(dsd_state * state, char * input);
|
||||||
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input);
|
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input);
|
||||||
@@ -1648,18 +1688,43 @@ void anytone_bp_keystream_creation(dsd_state * state, char * input);
|
|||||||
void baofeng_ap_pc5_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 csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24]);
|
||||||
void straight_mod_xor_keystream_creation(dsd_state * state, char * input);
|
void straight_mod_xor_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void caltta_bp_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void auctus_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void vertex_keystream_setup(dsd_state * state, char * input);
|
||||||
|
void vertex_40_keystream_creation(dsd_state * state, unsigned long long int key_value);
|
||||||
|
void vertex_256_keystream_creation(dsd_state * state, char * key_string);
|
||||||
|
void vtx256_ambe2_interleave_inversion(char ambe_fr[4][24]);
|
||||||
|
|
||||||
//Kirisun
|
//Kirisun LFSR and General Keystream Creator
|
||||||
uint32_t kirisun_lfsr(unsigned long long int mi);
|
uint32_t kirisun_lfsr(unsigned long long int mi);
|
||||||
void kirisun_adv_keystream_creation(dsd_state *state);
|
void kirisun_keystream_creation(dsd_state * state);
|
||||||
void kirisun_uni_keystream_creation(dsd_state *state);
|
|
||||||
|
|
||||||
//Hytera Enhanced
|
//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);
|
void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value, int len);
|
||||||
unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
|
unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
|
||||||
void hytera_enhanced_alg_refresh(dsd_state * state);
|
void hytera_enhanced_alg_refresh(dsd_state * state);
|
||||||
|
|
||||||
|
//RAS
|
||||||
|
uint32_t ras_mac_calculator(dsd_state * state, uint8_t * input, int input_len, int type);
|
||||||
|
void ras_effective_key_creation(dsd_state * state, char * input);
|
||||||
|
void ras_permute_order(uint32_t seed, int * order);
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
void hytera_ota_keystream_setup(dsd_state * state, char * input);
|
||||||
|
void hytera_ota_decrypt_bptc_96(dsd_state * state, uint8_t * input, uint8_t type);
|
||||||
|
void hytera_ota_decrypt_emb_lc(dsd_state * state, uint8_t input[8][16]);
|
||||||
|
void hytera_ota_search_emb_lc(dsd_state * state, uint8_t input[8][16]);
|
||||||
|
void hytera_ota_decrypt_sb_rc(dsd_state * state, uint8_t * input);
|
||||||
|
void hytera_ota_search_sb_rc(dsd_state * state, uint8_t * input, int ptype);
|
||||||
|
void hytera_create_lc_ctx(dsd_state * state, uint8_t * input);
|
||||||
|
void hytera_ota_unit_testing(dsd_state * state);
|
||||||
|
|
||||||
|
//Hytera Decryption for Data Blocks
|
||||||
|
uint8_t hytera_bp_data_decrypt(dsd_state * state, uint8_t * input, int len);
|
||||||
|
uint8_t hytera_ep_data_decrypt(dsd_opts * opts, dsd_state * state, uint8_t * input, int len);
|
||||||
|
|
||||||
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES
|
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES
|
||||||
|
void lfsr_32_to_128(uint8_t * iv);
|
||||||
void lfsr_64_to_128(uint8_t * iv);
|
void lfsr_64_to_128(uint8_t * iv);
|
||||||
void LFSR128(dsd_state * state);
|
void LFSR128(dsd_state * state);
|
||||||
void LFSR128n(dsd_state * state);
|
void LFSR128n(dsd_state * state);
|
||||||
@@ -1679,6 +1744,21 @@ void rtlsdr_sighandler();
|
|||||||
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
||||||
long int rtl_return_rms();
|
long int rtl_return_rms();
|
||||||
void rtl_clean_queue();
|
void rtl_clean_queue();
|
||||||
|
|
||||||
|
//rtl_tcp client (rtl_sdr_tcp.c)
|
||||||
|
int rtltcp_open(const char *hostname, int portno);
|
||||||
|
int rtlsdr_or_tcp_close(rtlsdr_dev_t *dev);
|
||||||
|
int rtlsdr_or_tcp_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx, uint32_t buf_num, uint32_t buf_len);
|
||||||
|
int rtlsdr_or_tcp_cancel_async(rtlsdr_dev_t *dev);
|
||||||
|
int rtlsdr_or_tcp_reset_buffer(rtlsdr_dev_t *dev);
|
||||||
|
int rtlsdr_or_tcp_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);
|
||||||
|
int rtlsdr_or_tcp_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
|
||||||
|
int rtlsdr_or_tcp_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);
|
||||||
|
int rtlsdr_or_tcp_set_direct_sampling(rtlsdr_dev_t *dev, int on);
|
||||||
|
int rtlsdr_or_tcp_set_offset_tuning(rtlsdr_dev_t *dev, int on);
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
|
||||||
|
int rtlsdr_or_tcp_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
671
src/bptc.c
671
src/bptc.c
@@ -167,223 +167,295 @@ void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief : This function extract the 96 bits of a deinteleaved 196 bits
|
* BPTC (196,96) extract — ETSI TS 102 361-1 B.1.1
|
||||||
* buffer using BPTC (196,96)
|
* Two-pass row Hamming(15,11) + column Hamming(13,9).
|
||||||
*
|
* Debug: define BPTC_196x96_DEBUG 1 for row/col correction chatter.
|
||||||
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (196 bytes)
|
|
||||||
*
|
|
||||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (96 bytes)
|
|
||||||
*
|
|
||||||
* @return The total number of irrecoverable Hamming check errors
|
|
||||||
*/
|
*/
|
||||||
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3])
|
|
||||||
|
// #define BPTC_196x96_DEBUG 1
|
||||||
|
|
||||||
|
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196],
|
||||||
|
uint8_t DMRDataExtracted[96],
|
||||||
|
uint8_t R[3],
|
||||||
|
uint8_t * is_ras)
|
||||||
{
|
{
|
||||||
uint32_t i, j, k;
|
uint32_t i, j, k;
|
||||||
uint8_t DataMatrix[13][15];
|
uint8_t DataMatrix[13][15];
|
||||||
uint8_t LineUncorrected[15];
|
uint8_t LineUncorrected[15];
|
||||||
|
uint8_t LineBefore[15];
|
||||||
uint8_t LineCorrected[11];
|
uint8_t LineCorrected[11];
|
||||||
uint8_t ColumnUncorrected[13];
|
uint8_t ColumnUncorrected[13];
|
||||||
|
uint8_t ColumnBefore[13];
|
||||||
uint8_t ColumnCorrected[9];
|
uint8_t ColumnCorrected[9];
|
||||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||||
|
uint32_t row_corr_p1 = 0, col_corr_p1 = 0;
|
||||||
|
uint32_t row_fail_p1 = 0, col_fail_p1 = 0;
|
||||||
|
uint32_t row_corr_p2 = 0, col_corr_p2 = 0;
|
||||||
|
uint32_t row_fail_p2 = 0, col_fail_p2 = 0;
|
||||||
|
|
||||||
/* First step : Reconstitute the BPTC 15x11 matrix
|
UNUSED(row_corr_p1); UNUSED(col_corr_p1);
|
||||||
* Note : Input data shall be deinterleaved */
|
UNUSED(row_fail_p1); UNUSED(col_fail_p1);
|
||||||
k = 1; /* Discard R(3) bit - See DMR standard chapter B1.1 BPTC (196,96) */
|
UNUSED(row_corr_p2); UNUSED(col_corr_p2);
|
||||||
for(i = 0; i < 13; i++)
|
UNUSED(row_fail_p2); UNUSED(col_fail_p2);
|
||||||
|
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Rebuild 13×15 matrix; discard R(3) at index 0 — DMR B.1.1 */
|
||||||
|
k = 1;
|
||||||
|
for (i = 0; i < 13; i++)
|
||||||
{
|
{
|
||||||
for(j = 0; j < 15; j++)
|
for (j = 0; j < 15; j++)
|
||||||
{
|
{
|
||||||
/* Only the LSBit of the byte is stored */
|
|
||||||
DataMatrix[i][j] = (InputDeInteleavedData[k] & 1);
|
DataMatrix[i][j] = (InputDeInteleavedData[k] & 1);
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
|
/* ========== Pass 1: row Hamming(15,11) on rows 0..8 ========== */
|
||||||
// DataMatrix[0][0] = 0; /* R(2) */
|
for (i = 0; i < 9; i++)
|
||||||
// DataMatrix[0][1] = 0; /* R(1) */
|
|
||||||
// DataMatrix[0][2] = 0; /* R(0) */
|
|
||||||
|
|
||||||
/* Init the Hamming (15,11,3) library
|
|
||||||
* Not needed because it has already been done
|
|
||||||
* in the "InitAllFecFunction()" function */
|
|
||||||
//Hamming_15_11_init();
|
|
||||||
|
|
||||||
/* Init the Hamming (13,9,3) library
|
|
||||||
* Not needed because it has already been done
|
|
||||||
* in the "InitAllFecFunction()" function */
|
|
||||||
//Hamming_13_9_init();
|
|
||||||
|
|
||||||
/* Init the Hamming error counter */
|
|
||||||
HammingIrrecoverableErrorNb = 0;
|
|
||||||
|
|
||||||
/* Process the the Hamming (15,11,3) code
|
|
||||||
* check on each line (first time).
|
|
||||||
* Do not check the 4th last lines */
|
|
||||||
for(i = 0; i < 9; i++)
|
|
||||||
{
|
{
|
||||||
/* Get a full line */
|
for (j = 0; j < 15; j++)
|
||||||
for(j = 0; j < 15; j++)
|
|
||||||
{
|
{
|
||||||
LineUncorrected[j] = DataMatrix[i][j];
|
LineUncorrected[j] = DataMatrix[i][j];
|
||||||
|
LineBefore[j] = LineUncorrected[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply Hamming (15,11,3) code correction */
|
if (Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||||
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
|
||||||
{
|
{
|
||||||
HammingIrrecoverableErrorNb++;
|
HammingIrrecoverableErrorNb++;
|
||||||
}
|
row_fail_p1++;
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
fprintf(stderr, " BPTC196 P1 ROW FAIL row=%u rx=", (unsigned)i);
|
||||||
* not the Hamming part [4 bit]) */
|
for (j = 0; j < 15; j++)
|
||||||
for(j = 0; j < 11; j++)
|
fprintf(stderr, "%u", LineBefore[j] & 1);
|
||||||
{
|
fprintf(stderr, "\n");
|
||||||
DataMatrix[i][j] = LineCorrected[j];
|
#endif
|
||||||
}
|
/* Keep original data bits on failure */
|
||||||
}
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineBefore[j];
|
||||||
|
|
||||||
/* Process the the Hamming (15,11,3) code
|
|
||||||
* check on each column/row (first time) */
|
|
||||||
for(i = 0; i < 15; i++)
|
|
||||||
{
|
|
||||||
/* Get a full column */
|
|
||||||
for(j = 0; j < 13; j++)
|
|
||||||
{
|
|
||||||
ColumnUncorrected[j] = DataMatrix[j][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply Hamming (15,11,3) code correction */
|
|
||||||
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
|
||||||
{
|
|
||||||
HammingIrrecoverableErrorNb++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Re-inject the column in the matrix (only the util data [11 bit],
|
|
||||||
* not the Hamming part [4 bit]) */
|
|
||||||
for(j = 0; j < 9; j++)
|
|
||||||
{
|
|
||||||
DataMatrix[j][i] = ColumnCorrected[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The first Hamming code check has maybe corrected bit
|
|
||||||
* witch can be use to correct other bit, so make the
|
|
||||||
* same operation twice */
|
|
||||||
|
|
||||||
/* Reset the number of irrecoverable errors */
|
|
||||||
HammingIrrecoverableErrorNb = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/* Process the the Hamming (15,11,3) code
|
|
||||||
* check on each line (second time).
|
|
||||||
* Do not check the 4th last lines */
|
|
||||||
for(i = 0; i < 9; i++)
|
|
||||||
{
|
|
||||||
/* Get a full line */
|
|
||||||
for(j = 0; j < 15; j++)
|
|
||||||
{
|
|
||||||
LineUncorrected[j] = DataMatrix[i][j];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply Hamming (15,11,3) code correction */
|
|
||||||
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
|
||||||
{
|
|
||||||
/* Row/Line contains irrecoverable errors */
|
|
||||||
HammingIrrecoverableErrorNb++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Row/Line contains correct data */
|
/* rxBits were corrected in place; note any flip */
|
||||||
}
|
for (j = 0; j < 15; j++)
|
||||||
|
{
|
||||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
if ((LineBefore[j] & 1) != (LineUncorrected[j] & 1))
|
||||||
* not the Hamming part [4 bit]) */
|
{
|
||||||
for(j = 0; j < 11; j++)
|
row_corr_p1++;
|
||||||
{
|
#if BPTC_196x96_DEBUG
|
||||||
DataMatrix[i][j] = LineCorrected[j];
|
fprintf(stderr,
|
||||||
|
" BPTC196 P1 ROW CORRECTED row=%u bit=%u %u->%u\n",
|
||||||
|
(unsigned)i, (unsigned)j,
|
||||||
|
(unsigned)(LineBefore[j] & 1),
|
||||||
|
(unsigned)(LineUncorrected[j] & 1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineCorrected[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
if (row_fail_p1 || row_corr_p1)
|
||||||
|
fprintf(stderr, " BPTC196 P1 ROW summary: fail=%u corrected_bits=%u\n",
|
||||||
|
(unsigned)row_fail_p1, (unsigned)row_corr_p1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========== Pass 1: column Hamming(13,9) on cols 0..14 ========== */
|
||||||
/* Process the the Hamming (15,11,3) code
|
for (i = 0; i < 15; i++)
|
||||||
* check on each column/row (second time) */
|
|
||||||
for(i = 0; i < 15; i++)
|
|
||||||
{
|
{
|
||||||
/* Get a full column */
|
for (j = 0; j < 13; j++)
|
||||||
for(j = 0; j < 13; j++)
|
|
||||||
{
|
{
|
||||||
ColumnUncorrected[j] = DataMatrix[j][i];
|
ColumnUncorrected[j] = DataMatrix[j][i];
|
||||||
|
ColumnBefore[j] = ColumnUncorrected[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply Hamming (15,11,3) code correction */
|
if (Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
||||||
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
|
||||||
{
|
{
|
||||||
/* Row/Line contains irrecoverable errors */
|
|
||||||
HammingIrrecoverableErrorNb++;
|
HammingIrrecoverableErrorNb++;
|
||||||
|
col_fail_p1++;
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
fprintf(stderr, " BPTC196 P1 COL FAIL col=%u rx=", (unsigned)i);
|
||||||
|
for (j = 0; j < 13; j++)
|
||||||
|
fprintf(stderr, "%u", ColumnBefore[j] & 1);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
for (j = 0; j < 9; j++)
|
||||||
|
DataMatrix[j][i] = ColumnBefore[j];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Row/Line contains correct data */
|
for (j = 0; j < 13; j++)
|
||||||
}
|
{
|
||||||
|
if ((ColumnBefore[j] & 1) != (ColumnUncorrected[j] & 1))
|
||||||
/* Re-inject the column in the matrix (only the util data [11 bit],
|
{
|
||||||
* not the Hamming part [4 bit]) */
|
col_corr_p1++;
|
||||||
for(j = 0; j < 9; j++)
|
#if BPTC_196x96_DEBUG
|
||||||
{
|
fprintf(stderr,
|
||||||
DataMatrix[j][i] = ColumnCorrected[j];
|
" BPTC196 P1 COL CORRECTED col=%u bit=%u %u->%u\n",
|
||||||
|
(unsigned)i, (unsigned)j,
|
||||||
|
(unsigned)(ColumnBefore[j] & 1),
|
||||||
|
(unsigned)(ColumnUncorrected[j] & 1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (j = 0; j < 9; j++)
|
||||||
|
DataMatrix[j][i] = ColumnCorrected[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
if (col_fail_p1 || col_corr_p1)
|
||||||
|
fprintf(stderr, " BPTC196 P1 COL summary: fail=%u corrected_bits=%u\n",
|
||||||
|
(unsigned)col_fail_p1, (unsigned)col_corr_p1);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Extract the DMR data (96 bit) from the matrix */
|
/* Second pass can fix more after the first cascade */
|
||||||
/* First line : Do not take R(2), R(1) and R(0) */
|
HammingIrrecoverableErrorNb = 0;
|
||||||
|
|
||||||
|
/* ========== Pass 2: rows ========== */
|
||||||
|
for (i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 15; j++)
|
||||||
|
{
|
||||||
|
LineUncorrected[j] = DataMatrix[i][j];
|
||||||
|
LineBefore[j] = LineUncorrected[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||||
|
{
|
||||||
|
HammingIrrecoverableErrorNb++;
|
||||||
|
row_fail_p2++;
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
fprintf(stderr, " BPTC196 P2 ROW FAIL row=%u rx=", (unsigned)i);
|
||||||
|
for (j = 0; j < 15; j++)
|
||||||
|
fprintf(stderr, "%u", LineBefore[j] & 1);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineBefore[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (j = 0; j < 15; j++)
|
||||||
|
{
|
||||||
|
if ((LineBefore[j] & 1) != (LineUncorrected[j] & 1))
|
||||||
|
{
|
||||||
|
row_corr_p2++;
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC196 P2 ROW CORRECTED row=%u bit=%u %u->%u\n",
|
||||||
|
(unsigned)i, (unsigned)j,
|
||||||
|
(unsigned)(LineBefore[j] & 1),
|
||||||
|
(unsigned)(LineUncorrected[j] & 1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineCorrected[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
if (row_fail_p2 || row_corr_p2)
|
||||||
|
fprintf(stderr, " BPTC196 P2 ROW summary: fail=%u corrected_bits=%u\n",
|
||||||
|
(unsigned)row_fail_p2, (unsigned)row_corr_p2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========== Pass 2: columns ========== */
|
||||||
|
for (i = 0; i < 15; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 13; j++)
|
||||||
|
{
|
||||||
|
ColumnUncorrected[j] = DataMatrix[j][i];
|
||||||
|
ColumnBefore[j] = ColumnUncorrected[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
||||||
|
{
|
||||||
|
HammingIrrecoverableErrorNb++;
|
||||||
|
col_fail_p2++;
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
fprintf(stderr, " BPTC196 P2 COL FAIL col=%u rx=", (unsigned)i);
|
||||||
|
for (j = 0; j < 13; j++)
|
||||||
|
fprintf(stderr, "%u", ColumnBefore[j] & 1);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
for (j = 0; j < 9; j++)
|
||||||
|
DataMatrix[j][i] = ColumnBefore[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (j = 0; j < 13; j++)
|
||||||
|
{
|
||||||
|
if ((ColumnBefore[j] & 1) != (ColumnUncorrected[j] & 1))
|
||||||
|
{
|
||||||
|
col_corr_p2++;
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC196 P2 COL CORRECTED col=%u bit=%u %u->%u\n",
|
||||||
|
(unsigned)i, (unsigned)j,
|
||||||
|
(unsigned)(ColumnBefore[j] & 1),
|
||||||
|
(unsigned)(ColumnUncorrected[j] & 1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (j = 0; j < 9; j++)
|
||||||
|
DataMatrix[j][i] = ColumnCorrected[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if BPTC_196x96_DEBUG
|
||||||
|
if (col_fail_p2 || col_corr_p2)
|
||||||
|
fprintf(stderr, " BPTC196 P2 COL summary: fail=%u corrected_bits=%u\n",
|
||||||
|
(unsigned)col_fail_p2, (unsigned)col_corr_p2);
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC196 FINAL irrecoverable=%u P1(row_f=%u col_f=%u row_c=%u col_c=%u) "
|
||||||
|
"P2(row_f=%u col_f=%u row_c=%u col_c=%u)\n",
|
||||||
|
(unsigned)HammingIrrecoverableErrorNb,
|
||||||
|
(unsigned)row_fail_p1, (unsigned)col_fail_p1,
|
||||||
|
(unsigned)row_corr_p1, (unsigned)col_corr_p1,
|
||||||
|
(unsigned)row_fail_p2, (unsigned)col_fail_p2,
|
||||||
|
(unsigned)row_corr_p2, (unsigned)col_corr_p2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Extract 96 data bits */
|
||||||
k = 0;
|
k = 0;
|
||||||
|
for (i = 3; i < 11; i++)
|
||||||
for(i = 3; i < 11; i++)
|
|
||||||
{
|
{
|
||||||
DMRDataExtracted[k] = DataMatrix[0][i];
|
DMRDataExtracted[k++] = DataMatrix[0][i];
|
||||||
k++;
|
}
|
||||||
|
for (i = 1; i < 9; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DMRDataExtracted[k++] = DataMatrix[i][j];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next lines */
|
if (HammingIrrecoverableErrorNb == 0)
|
||||||
for(i = 1; i < 9; i++)
|
|
||||||
{
|
{
|
||||||
for(j = 0; j < 11; j++)
|
R[0] = DataMatrix[0][2]; /* R(0) */
|
||||||
{
|
R[1] = DataMatrix[0][1]; /* R(1) */
|
||||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
R[2] = DataMatrix[0][0]; /* R(2) */
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* R(0) to R(2) may be used to transport some
|
if (R[0] == 0 && R[1] == 0 && R[2] == 1)
|
||||||
* Restricted Access System (RAS) information,
|
*is_ras = 1;
|
||||||
* So save these three bits after hamming correction
|
else
|
||||||
* See patent US 2013/0288643 A1 */
|
*is_ras = 0;
|
||||||
R[0] = DataMatrix[0][2]; /* Save R(0) */
|
|
||||||
R[1] = DataMatrix[0][1]; /* Save R(1) */
|
|
||||||
R[2] = DataMatrix[0][0]; /* Save R(2) */
|
|
||||||
|
|
||||||
/* Return the number of irrecoverable Hamming errors */
|
|
||||||
return HammingIrrecoverableErrorNb;
|
return HammingIrrecoverableErrorNb;
|
||||||
} /* End BPTC_196x96_Extract_Data() */
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief : This function extract the 77 bits of a deinteleaved 128 bits
|
* BPTC (128,77) extract with iterative Hamming + parity-guided repair
|
||||||
* buffer using BPTC (128,77).
|
* and diagnostic logging.
|
||||||
|
* See ETSI TS 102 361-1 B.2.1
|
||||||
*
|
*
|
||||||
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.1 for details
|
* Enable/disable chatter with BPTC_128x77_DEBUG (1 = on).
|
||||||
*
|
|
||||||
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (128 bytes
|
|
||||||
act as a 16 x 8 byte data matrix)
|
|
||||||
*
|
|
||||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
|
|
||||||
* DMRDataExtracted[0..71] = Util data (hamming corrected)
|
|
||||||
* DMRDataExtracted[72..76] = 5 bit of CRC extracted (to be checked)
|
|
||||||
*
|
|
||||||
* @return 0 = All is OK
|
|
||||||
* Other = Error - Irrecoverable Hamming parity check error number
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// #define BPTC_128x77_DEBUG 1
|
||||||
|
|
||||||
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77])
|
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77])
|
||||||
{
|
{
|
||||||
uint32_t i, j, k;
|
uint32_t i, j, k;
|
||||||
@@ -394,102 +466,193 @@ uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDat
|
|||||||
uint32_t ParityCheckErrorNb = 0;
|
uint32_t ParityCheckErrorNb = 0;
|
||||||
uint32_t NbOfOne;
|
uint32_t NbOfOne;
|
||||||
|
|
||||||
/* First step : Reconstitute the BPTC 16x8 matrix */
|
uint8_t row_bad[7];
|
||||||
for(i = 0; i < 8; i++)
|
uint8_t col_bad[16];
|
||||||
|
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
for(j = 0; j < 16; j++)
|
for (j = 0; j < 16; j++)
|
||||||
{
|
|
||||||
/* Only the LSBit of the byte is stored */
|
|
||||||
DataMatrix[i][j] = (InputDataMatrix[i][j] & 1);
|
DataMatrix[i][j] = (InputDataMatrix[i][j] & 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init the Hamming (16,11,4) library
|
/* ---------- Pass 1: Hamming (16,11,4) on rows 0..6 ---------- */
|
||||||
* Not needed because it has already been done
|
memset(row_bad, 0, sizeof(row_bad));
|
||||||
* in the "InitAllFecFunction()" function */
|
for (i = 0; i < 7; i++)
|
||||||
//Hamming_16_11_4_init();
|
|
||||||
|
|
||||||
/* Process the the Hamming (16,11,4) code
|
|
||||||
* check on each line.
|
|
||||||
* Do not check the last line (line nb 8) */
|
|
||||||
for(i = 0; i < 7; i++)
|
|
||||||
{
|
{
|
||||||
/* Get a full line */
|
for (j = 0; j < 16; j++)
|
||||||
for(j = 0; j < 16; j++)
|
|
||||||
{
|
|
||||||
LineUncorrected[j] = DataMatrix[i][j];
|
LineUncorrected[j] = DataMatrix[i][j];
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply Hamming (16,11,4) code correction */
|
if (Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||||
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
|
||||||
{
|
{
|
||||||
HammingIrrecoverableErrorNb++;
|
HammingIrrecoverableErrorNb++;
|
||||||
|
row_bad[i] = 1;
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf(stderr, " BPTC128 P1 Hamming FAIL row=%u rx=", (unsigned)i);
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
fprintf(stderr, "%u", LineUncorrected[j] & 1);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineUncorrected[j];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
|
||||||
* not the Hamming part [4 bit]) */
|
|
||||||
for(j = 0; j < 11; j++)
|
|
||||||
{
|
{
|
||||||
DataMatrix[i][j] = LineCorrected[j];
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineCorrected[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
if (HammingIrrecoverableErrorNb)
|
||||||
|
fprintf(stderr, " BPTC128 P1 Hamming irrecoverable rows=%u\n",
|
||||||
|
(unsigned)HammingIrrecoverableErrorNb);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Extract the DMR data (77 bit) from the matrix */
|
/* ---------- Column even-parity check (row 7) ---------- */
|
||||||
k = 0;
|
memset(col_bad, 0, sizeof(col_bad));
|
||||||
|
|
||||||
/* 2 first lines */
|
|
||||||
for(i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < 11; j++)
|
|
||||||
{
|
|
||||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 5 Next lines */
|
|
||||||
for(i = 2; i < 7; i++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < 10; j++)
|
|
||||||
{
|
|
||||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 5 bit of CRC */
|
|
||||||
for(i = 2; i < 7; i++)
|
|
||||||
{
|
|
||||||
DMRDataExtracted[k] = DataMatrix[i][10];
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the data integrity by checking
|
|
||||||
* all column parity bit */
|
|
||||||
ParityCheckErrorNb = 0;
|
ParityCheckErrorNb = 0;
|
||||||
for(i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
NbOfOne = 0;
|
NbOfOne = 0;
|
||||||
|
for (j = 0; j < 7; j++)
|
||||||
/* Get a full column */
|
|
||||||
for(j = 0; j < 7; j++)
|
|
||||||
{
|
|
||||||
NbOfOne += DataMatrix[j][i];
|
NbOfOne += DataMatrix[j][i];
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the parity bit (number of "1"
|
if ((NbOfOne % 2) != DataMatrix[7][i])
|
||||||
* must be even) */
|
|
||||||
if((NbOfOne % 2) != DataMatrix[7][i])
|
|
||||||
{
|
{
|
||||||
ParityCheckErrorNb++;
|
ParityCheckErrorNb++;
|
||||||
|
col_bad[i] = 1;
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC128 P1 parity FAIL col=%u sum7=%u parity_bit=%u (expect even)\n",
|
||||||
|
(unsigned)i, (unsigned)NbOfOne, (unsigned)DataMatrix[7][i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
if (ParityCheckErrorNb)
|
||||||
|
fprintf(stderr, " BPTC128 P1 parity bad columns=%u\n",
|
||||||
|
(unsigned)ParityCheckErrorNb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------- Parity-guided single-bit repair ---------- */
|
||||||
|
{
|
||||||
|
uint32_t n_bad_rows = 0, n_bad_cols = 0;
|
||||||
|
uint32_t br = 0, bc = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
if (row_bad[i]) { n_bad_rows++; br = i; }
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
if (col_bad[i]) { n_bad_cols++; bc = i; }
|
||||||
|
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC128 repair candidates: bad_rows=%u bad_cols=%u",
|
||||||
|
(unsigned)n_bad_rows, (unsigned)n_bad_cols);
|
||||||
|
if (n_bad_rows == 1)
|
||||||
|
fprintf(stderr, " row=%u", (unsigned)br);
|
||||||
|
if (n_bad_cols == 1)
|
||||||
|
fprintf(stderr, " col=%u", (unsigned)bc);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (n_bad_rows == 1 && n_bad_cols == 1 && bc < 11)
|
||||||
|
{
|
||||||
|
DataMatrix[br][bc] ^= 1;
|
||||||
|
row_bad[br] = 0;
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC128 parity-guided FLIP at row=%u col=%u -> %u\n",
|
||||||
|
(unsigned)br, (unsigned)bc, (unsigned)DataMatrix[br][bc]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
else if (n_bad_rows || n_bad_cols)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC128 no single-intersection flip "
|
||||||
|
"(need exactly 1 bad row and 1 data col)\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Pass 2: Hamming (16,11,4) again ---------- */
|
||||||
|
HammingIrrecoverableErrorNb = 0;
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
LineUncorrected[j] = DataMatrix[i][j];
|
||||||
|
|
||||||
|
if (Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||||
|
{
|
||||||
|
HammingIrrecoverableErrorNb++;
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf(stderr, " BPTC128 P2 Hamming FAIL row=%u rx=", (unsigned)i);
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
fprintf(stderr, "%u", LineUncorrected[j] & 1);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineUncorrected[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DataMatrix[i][j] = LineCorrected[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
if (HammingIrrecoverableErrorNb)
|
||||||
|
fprintf(stderr, " BPTC128 P2 Hamming irrecoverable rows=%u\n",
|
||||||
|
(unsigned)HammingIrrecoverableErrorNb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------- Final column parity recount ---------- */
|
||||||
|
ParityCheckErrorNb = 0;
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
NbOfOne = 0;
|
||||||
|
for (j = 0; j < 7; j++)
|
||||||
|
NbOfOne += DataMatrix[j][i];
|
||||||
|
|
||||||
|
if ((NbOfOne % 2) != DataMatrix[7][i])
|
||||||
|
{
|
||||||
|
ParityCheckErrorNb++;
|
||||||
|
#if BPTC_128x77_DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
" BPTC128 P2 parity FAIL col=%u sum7=%u parity_bit=%u\n",
|
||||||
|
(unsigned)i, (unsigned)NbOfOne, (unsigned)DataMatrix[7][i]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of irrecoverable Hamming errors +
|
#if BPTC_128x77_DEBUG
|
||||||
* the number of parity check error */
|
fprintf(stderr,
|
||||||
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
" BPTC128 result: Hamming_err=%u parity_err=%u total=%u\n",
|
||||||
} /* End BPTC_128x77_Extract_Data() */
|
(unsigned)HammingIrrecoverableErrorNb,
|
||||||
|
(unsigned)ParityCheckErrorNb,
|
||||||
|
(unsigned)(HammingIrrecoverableErrorNb + ParityCheckErrorNb));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------- Extract 77 bits ---------- */
|
||||||
|
k = 0;
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 11; j++)
|
||||||
|
DMRDataExtracted[k++] = DataMatrix[i][j];
|
||||||
|
}
|
||||||
|
for (i = 2; i < 7; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 10; j++)
|
||||||
|
DMRDataExtracted[k++] = DataMatrix[i][j];
|
||||||
|
}
|
||||||
|
for (i = 2; i < 7; i++)
|
||||||
|
DMRDataExtracted[k++] = DataMatrix[i][10];
|
||||||
|
|
||||||
|
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief : This function extract the 32 bits of a deinteleaved 32 bits
|
* @brief : This function extract the 32 bits of a deinteleaved 32 bits
|
||||||
@@ -577,6 +740,52 @@ uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDat
|
|||||||
|
|
||||||
} /* End BPTC_16x2_Extract_Data() */
|
} /* End BPTC_16x2_Extract_Data() */
|
||||||
|
|
||||||
|
uint32_t BPTC_128x77_Check_Errors(uint8_t InputDataMatrix[8][16])
|
||||||
|
{
|
||||||
|
uint32_t i, j;
|
||||||
|
uint32_t ham_bad = 0, ham_fix = 0, par_err = 0;
|
||||||
|
uint8_t line[16], before[16], decoded[11];
|
||||||
|
uint32_t ones;
|
||||||
|
int changed;
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
before[j] = (InputDataMatrix[i][j] & 1);
|
||||||
|
line[j] = before[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Hamming_16_11_4_decode(line, decoded, 1) == false)
|
||||||
|
{
|
||||||
|
ham_bad++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
changed = 0;
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
if (line[j] != before[j])
|
||||||
|
{
|
||||||
|
changed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
|
ham_fix++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
ones = 0;
|
||||||
|
for (j = 0; j < 7; j++)
|
||||||
|
ones += (InputDataMatrix[j][i] & 1);
|
||||||
|
if ((ones % 2) != (InputDataMatrix[7][i] & 1))
|
||||||
|
par_err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ham_bad + ham_fix + par_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* End of file */
|
/* End of file */
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
#include "bp.h"
|
||||||
|
|
||||||
#define AES_BLOCKLEN 16
|
#define AES_BLOCKLEN 16
|
||||||
unsigned Nb = 4;
|
unsigned Nb = 4;
|
||||||
@@ -510,6 +511,57 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Vertex Standard "AES" Encryption - convert AES key into a round key at 256 Nb,Nk,Nr values
|
||||||
|
//then select entries from the BP table to invert and convert to a keystream
|
||||||
|
void vertex_256_keystream_creation(dsd_state * state, char * key_string)
|
||||||
|
{
|
||||||
|
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
|
||||||
|
uint8_t key[32];
|
||||||
|
memset (key, 0, sizeof(key));
|
||||||
|
|
||||||
|
parse_raw_user_string(key_string, key);
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
|
||||||
|
uint64_t vtx_key = 0;
|
||||||
|
|
||||||
|
//use the bytes from round key output to select 4 BP key 16-bit words
|
||||||
|
for (int i = 224; i < 228; i++)
|
||||||
|
{
|
||||||
|
vtx_key <<= 16;
|
||||||
|
vtx_key |= BPK[ctx.RoundKey[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
//invert value
|
||||||
|
vtx_key = ~vtx_key;
|
||||||
|
|
||||||
|
fprintf (stderr,"Vertex Round Key Bytes: ");
|
||||||
|
for (uint16_t i = 224; i < 228; i++)
|
||||||
|
fprintf (stderr, "%02X ", ctx.RoundKey[i]);
|
||||||
|
fprintf (stderr, "Vertex Keystream: %016llX;", (unsigned long long int)vtx_key);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
uint8_t vtx_bytes[8];
|
||||||
|
memset (vtx_bytes, 0, sizeof(vtx_bytes));
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vtx_bytes[i] = (vtx_key >> (56-(i*8))) & 0xFF;
|
||||||
|
|
||||||
|
unpack_byte_array_into_bit_array(vtx_bytes, state->static_ks_bits[0], 8);
|
||||||
|
unpack_byte_array_into_bit_array(vtx_bytes, state->static_ks_bits[1], 8);
|
||||||
|
|
||||||
|
//hex representation of the effective keystream value
|
||||||
|
state->vtx256_ekey = convert_bits_into_output(state->static_ks_bits[0], 64);
|
||||||
|
|
||||||
|
state->vtx_key_loaded = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//byte-wise output of AES OFB Keystream
|
//byte-wise output of AES OFB Keystream
|
||||||
//input iv is a 16-byte uint8_t array of initialization vector
|
//input iv is a 16-byte uint8_t array of initialization vector
|
||||||
//input key is up to 32-byte uint8_t array of key value
|
//input key is up to 32-byte uint8_t array of key value
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ void des_cipher (uint8_t * main_key, uint8_t * input_register, uint8_t * output_
|
|||||||
memcpy (left, initial_permutation+0, sizeof(left));
|
memcpy (left, initial_permutation+0, sizeof(left));
|
||||||
memcpy (right, initial_permutation+4, sizeof(right));
|
memcpy (right, initial_permutation+4, sizeof(right));
|
||||||
|
|
||||||
//16 fiestel rounds
|
//16 feistel rounds
|
||||||
for (uint8_t f = 0; f < 16; f++)
|
for (uint8_t f = 0; f < 16; f++)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -339,7 +339,102 @@ void des_cipher (uint8_t * main_key, uint8_t * input_register, uint8_t * output_
|
|||||||
memcpy (left, right, sizeof(left));
|
memcpy (left, right, sizeof(left));
|
||||||
memcpy (right, rperm, sizeof(right));
|
memcpy (right, rperm, sizeof(right));
|
||||||
|
|
||||||
} //end fiestel rounds f
|
} //end feistel rounds f
|
||||||
|
|
||||||
|
//combine right and left into the pre_end_permutation array
|
||||||
|
memcpy (pre_end_permutation+0, right, sizeof(right));
|
||||||
|
memcpy (pre_end_permutation+4, left, sizeof(left));
|
||||||
|
|
||||||
|
//carry out the final permuation to get the completed output_register for this cipher iteration
|
||||||
|
permute (pre_end_permutation, output_register, final_register_permutation, 0, 64);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//kirisun variation on this cipher w/ preconfigured unique key schedule
|
||||||
|
void ksun_des_cipher (uint8_t * key, uint8_t * input_register, uint8_t * output_register, uint8_t de)
|
||||||
|
{
|
||||||
|
|
||||||
|
//starting and ending permutations
|
||||||
|
uint8_t initial_permutation[8]; memset(initial_permutation, 0, sizeof(initial_permutation));
|
||||||
|
uint8_t pre_end_permutation[8]; memset(pre_end_permutation, 0, sizeof(pre_end_permutation));
|
||||||
|
|
||||||
|
//intermediate left, right, and expansion/selection arrays
|
||||||
|
uint8_t left[4]; memset(left, 0, sizeof(left));
|
||||||
|
uint8_t right[4]; memset(right, 0, sizeof(right));
|
||||||
|
uint8_t rperm[4]; memset(rperm, 0, sizeof(rperm));
|
||||||
|
uint8_t exp[6]; memset(exp, 0, sizeof(exp));
|
||||||
|
uint8_t sel[4]; memset(sel, 0, sizeof(sel));
|
||||||
|
|
||||||
|
//key sets
|
||||||
|
uint8_t Ks[16][6]; memset(Ks, 0, sizeof(Ks));
|
||||||
|
|
||||||
|
//file the key into the keysets
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 6; j++)
|
||||||
|
Ks[i][j] = key[(i*6) + j];
|
||||||
|
}
|
||||||
|
|
||||||
|
//permute the input_register with the ip (initial_register_permutation) table
|
||||||
|
permute (input_register, initial_permutation, initial_register_permutation, 0, 64);
|
||||||
|
|
||||||
|
//copy the initial permutation to left and right half arrays
|
||||||
|
memcpy (left, initial_permutation+0, sizeof(left));
|
||||||
|
memcpy (right, initial_permutation+4, sizeof(right));
|
||||||
|
|
||||||
|
//16 feistel rounds
|
||||||
|
for (uint8_t f = 0; f < 16; f++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//reset rperm and exp arrays
|
||||||
|
memset(rperm, 0, sizeof(rperm));
|
||||||
|
memset(exp, 0, sizeof(exp));
|
||||||
|
|
||||||
|
//expand right half from 32-bit to 48-bit
|
||||||
|
permute (right, exp, message_expansion, 0, 48);
|
||||||
|
|
||||||
|
//apply current iteration keyset to the expanded array (encryption cycles Ks forward, decryption goes in reverse)
|
||||||
|
if (de == 1)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
exp[i] ^= Ks[f][i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
exp[i] ^= Ks[15-f][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//extract 6 bits for each sbox swap from the expanded array
|
||||||
|
uint8_t e1 = exp[0] >> 2;
|
||||||
|
uint8_t e2 = ((exp[0] & 0x3) << 4) | (exp[1] >> 4);
|
||||||
|
uint8_t e3 = ((exp[1] & 0xF) << 2) | (exp[2] >> 6);
|
||||||
|
uint8_t e4 = exp[2] & 0x3F;
|
||||||
|
|
||||||
|
uint8_t e5 = exp[3] >> 2;
|
||||||
|
uint8_t e6 = ((exp[3] & 0x3) << 4) | (exp[4] >> 4);
|
||||||
|
uint8_t e7 = ((exp[4] & 0xF) << 2) | (exp[5] >> 6);
|
||||||
|
uint8_t e8 = exp[5] & 0x3F;
|
||||||
|
|
||||||
|
//select 32-bits of each 48-bit expansion via modified S Box Look Up Tables
|
||||||
|
//swap the 6 bits for 4 bits via SLUT tables and OR them together into a selection array
|
||||||
|
sel[0] = SLUT1[e1] | SLUT2[e2];
|
||||||
|
sel[1] = SLUT3[e3] | SLUT4[e4];
|
||||||
|
sel[2] = SLUT5[e5] | SLUT6[e6];
|
||||||
|
sel[3] = SLUT7[e7] | SLUT8[e8];
|
||||||
|
|
||||||
|
//permute the selected 32-bits into a new right half
|
||||||
|
permute (sel, rperm, right_half_permutation, 0, 32);
|
||||||
|
|
||||||
|
//xor new right half against left half
|
||||||
|
for (uint8_t i = 0; i < 4; i++)
|
||||||
|
rperm[i] ^= left[i];
|
||||||
|
|
||||||
|
//swap old right half to left, set new right half to rperm
|
||||||
|
memcpy (left, right, sizeof(left));
|
||||||
|
memcpy (right, rperm, sizeof(right));
|
||||||
|
|
||||||
|
} //end feistel rounds f
|
||||||
|
|
||||||
//combine right and left into the pre_end_permutation array
|
//combine right and left into the pre_end_permutation array
|
||||||
memcpy (pre_end_permutation+0, right, sizeof(right));
|
memcpy (pre_end_permutation+0, right, sizeof(right));
|
||||||
|
|||||||
228
src/crypt-etc.c
228
src/crypt-etc.c
@@ -1,4 +1,5 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
#include "dmr_const.h"
|
||||||
|
|
||||||
void ken_dmr_scrambler_keystream_creation(dsd_state * state, char * input)
|
void ken_dmr_scrambler_keystream_creation(dsd_state * state, char * input)
|
||||||
{
|
{
|
||||||
@@ -92,6 +93,9 @@ void straight_mod_xor_keystream_creation(dsd_state * state, char * input)
|
|||||||
}
|
}
|
||||||
else goto END_KS;
|
else goto END_KS;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\ncurr: %s\n", curr);
|
||||||
|
|
||||||
uint8_t ks_bytes[112];
|
uint8_t ks_bytes[112];
|
||||||
memset (ks_bytes, 0, sizeof(ks_bytes));
|
memset (ks_bytes, 0, sizeof(ks_bytes));
|
||||||
parse_raw_user_string(curr, ks_bytes);
|
parse_raw_user_string(curr, ks_bytes);
|
||||||
@@ -122,5 +126,229 @@ void straight_mod_xor_keystream_creation(dsd_state * state, char * input)
|
|||||||
|
|
||||||
if (curr == NULL)
|
if (curr == NULL)
|
||||||
fprintf (stderr, "Straight KS String Malformed! No KS Created!\n");
|
fprintf (stderr, "Straight KS String Malformed! No KS Created!\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr = strtok(NULL, ":"); //optional discard value
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
len = 0;
|
||||||
|
sscanf (curr, "%hd", &len);
|
||||||
|
if (len != 0 && len < 8)
|
||||||
|
{
|
||||||
|
state->straight_discard = (int)len;
|
||||||
|
fprintf (stderr, "Optional Straight XOR Keystream Discard: %d; \n", len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void caltta_bp_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
uint16_t len = 0;
|
||||||
|
char * curr;
|
||||||
|
curr = strtok(input, ":"); //should be len (mod) of key (decimal)
|
||||||
|
if (curr != NULL)
|
||||||
|
sscanf (curr, "%hd", &len);
|
||||||
|
else goto END_KS;
|
||||||
|
|
||||||
|
//len sanity check, can't be greater than 882
|
||||||
|
if (len > 256)
|
||||||
|
len = 256;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //should be key in hex
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
//continue
|
||||||
|
}
|
||||||
|
else goto END_KS;
|
||||||
|
|
||||||
|
uint8_t ks_bytes[112];
|
||||||
|
memset (ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
parse_raw_user_string(curr, ks_bytes);
|
||||||
|
|
||||||
|
uint8_t ks_bits[896];
|
||||||
|
memset(ks_bits, 0, sizeof(ks_bits));
|
||||||
|
|
||||||
|
uint16_t unpack_len = len / 8;
|
||||||
|
if (len % 8)
|
||||||
|
unpack_len++;
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes, ks_bits, unpack_len);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
state->static_ks_bits[0][i] = ks_bits[i];
|
||||||
|
state->static_ks_bits[1][i] = ks_bits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr,"Caltta BP %d-bit Keystream: ", len);
|
||||||
|
for (uint16_t i = 0; i < unpack_len; i++)
|
||||||
|
fprintf (stderr, "%02X", ks_bytes[i]);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
state->straight_ks = 0x26;
|
||||||
|
state->straight_mod = (int)len;
|
||||||
|
|
||||||
|
END_KS:
|
||||||
|
|
||||||
|
if (curr == NULL)
|
||||||
|
fprintf (stderr, "Caltta BP KS String Malformed! No KS Created!\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void hytera_bp_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
uint16_t len = 0;
|
||||||
|
char * curr;
|
||||||
|
curr = strtok(input, ":"); //should be len (mod) of key (decimal)
|
||||||
|
if (curr != NULL)
|
||||||
|
sscanf (curr, "%hd", &len);
|
||||||
|
else goto END_KS;
|
||||||
|
|
||||||
|
//len sanity check, can't be greater than 882
|
||||||
|
if (len > 256)
|
||||||
|
len = 256;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //should be key in hex
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
//continue
|
||||||
|
}
|
||||||
|
else goto END_KS;
|
||||||
|
|
||||||
|
uint8_t ks_bytes[112];
|
||||||
|
memset (ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
parse_raw_user_string(curr, ks_bytes);
|
||||||
|
|
||||||
|
uint8_t ks_bits[896];
|
||||||
|
memset(ks_bits, 0, sizeof(ks_bits));
|
||||||
|
|
||||||
|
uint16_t unpack_len = len / 8;
|
||||||
|
if (len % 8)
|
||||||
|
unpack_len++;
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes, ks_bits, unpack_len);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
state->static_ks_bits[0][i] = ks_bits[i];
|
||||||
|
state->static_ks_bits[1][i] = ks_bits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr,"Hytera BP %d-bit Keystream: ", len);
|
||||||
|
for (uint16_t i = 0; i < unpack_len; i++)
|
||||||
|
fprintf (stderr, "%02X", ks_bytes[i]);
|
||||||
|
|
||||||
|
state->straight_ks = 0x68;
|
||||||
|
state->straight_mod = (int)len;
|
||||||
|
|
||||||
|
END_KS:
|
||||||
|
|
||||||
|
if (curr == NULL)
|
||||||
|
fprintf (stderr, "Hytera BP KS String Malformed! No KS Created!\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtx256_ambe2_interleave_inversion(char ambe_fr[4][24])
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t silence_check = 0;
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
silence_check <<= 1;
|
||||||
|
silence_check |= (uint8_t)ambe_fr[0][23-i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (silence_check == 0xF8014)
|
||||||
|
goto END_INV;
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//invert the bits in the 49 to 71 position
|
||||||
|
for (int8_t i = 49; i < 72; i++)
|
||||||
|
interleaved[i] ^= 1;
|
||||||
|
|
||||||
|
//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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
END_INV: ; //do nothing
|
||||||
|
|
||||||
}
|
}
|
||||||
833
src/crypt-kir.c
833
src/crypt-kir.c
@@ -1,6 +1,9 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
#include "pc4.h"
|
#include "pc4.h"
|
||||||
|
|
||||||
|
//function prototype linked in crypt-des.c
|
||||||
|
void ksun_des_cipher (uint8_t * key, uint8_t * input_register, uint8_t * output_register, uint8_t de);
|
||||||
|
|
||||||
/* === Global MD2II buffers === */
|
/* === Global MD2II buffers === */
|
||||||
int x1, x2, i, n1global;
|
int x1, x2, i, n1global;
|
||||||
unsigned char h2[n1];
|
unsigned char h2[n1];
|
||||||
@@ -174,8 +177,69 @@ void keystream37(unsigned char *key, uint64_t frame, unsigned char *output)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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'
|
#define ROTATE_LEFT(VALUE, SHIFT) \
|
||||||
void kirisun_uni_keystream_creation(dsd_state *state)
|
(((VALUE) << ((SHIFT) & 63)) | ((VALUE) >> (64 - ((SHIFT) & 63))))
|
||||||
|
|
||||||
|
#define ROTATE_RIGHT(VALUE, SHIFT) \
|
||||||
|
(((VALUE) >> ((SHIFT) & 63)) | ((VALUE) << (64 - ((SHIFT) & 63))))
|
||||||
|
|
||||||
|
void keystream35(uint8_t * input_register, unsigned char * key)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t round = 0x9E3779B97F4A7C15;
|
||||||
|
uint64_t round_key[2]; memset(round_key, 0, sizeof(round_key));
|
||||||
|
|
||||||
|
uint64_t state[2]; memset(state, 0, sizeof(state));
|
||||||
|
|
||||||
|
//load input_register into state as two 64-bit chunks
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
state[0] <<= 8;
|
||||||
|
state[0] |= input_register[i+0];
|
||||||
|
|
||||||
|
state[1] <<= 8;
|
||||||
|
state[1] |= input_register[i+8];
|
||||||
|
}
|
||||||
|
|
||||||
|
//load key into round_key as two 64-bit chunks
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
round_key[0] <<= 8;
|
||||||
|
round_key[0] |= key[i+0];
|
||||||
|
|
||||||
|
round_key[1] <<= 8;
|
||||||
|
round_key[1] |= key[i+8];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
round_key[0] += round;
|
||||||
|
round_key[1] -= round;
|
||||||
|
|
||||||
|
state[0] ^= round_key[0];
|
||||||
|
state[0] += state[1];
|
||||||
|
state[0] = ROTATE_LEFT(state[0], state[1]);
|
||||||
|
|
||||||
|
state[1] = ROTATE_RIGHT(state[1], state[0]);
|
||||||
|
state[1] -= state[0];
|
||||||
|
state[1] ^= round_key[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t temp = state[0];
|
||||||
|
state[0] = state[1];
|
||||||
|
state[1] = temp;
|
||||||
|
|
||||||
|
//reload input_register with current state values
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
input_register[i+0] = (state[0] >> (56 - (i * 8))) & 0xFF;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
input_register[i+8] = (state[1] >> (56 - (i * 8))) & 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//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_universal_keystream_creation(dsd_state *state)
|
||||||
{
|
{
|
||||||
uint8_t slot = 0;
|
uint8_t slot = 0;
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
@@ -292,8 +356,8 @@ void kirisun_uni_keystream_creation(dsd_state *state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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'
|
//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)
|
void kirisun_advanced_keystream_creation(dsd_state *state)
|
||||||
{
|
{
|
||||||
|
|
||||||
uint8_t slot = 0;
|
uint8_t slot = 0;
|
||||||
@@ -415,3 +479,764 @@ void kirisun_adv_keystream_creation(dsd_state *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//dsd-fme -fs -Z -i 'SSD_STORAGE/2025_DEV/Tytera BP EP AP Master Folder/kirisun/enhanced-key-12.wav/enhanced-key-12.wav' -H 'C607727B8BECC3CB 7DD174F5526BB546'
|
||||||
|
void kirisun_enhanced_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[128]; 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];
|
||||||
|
|
||||||
|
if (K1 != 0 && K2 != 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]);
|
||||||
|
|
||||||
|
// printf("=== userkey input (16 bytes) ===\n");
|
||||||
|
// print_hex(userkeyhexa,16);
|
||||||
|
|
||||||
|
/* --- MD2II first pass --- */
|
||||||
|
n1global=16;
|
||||||
|
unsigned char h4[n1]; memset(h4, 0, sizeof(h4));
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(userkeyhexa,16);
|
||||||
|
MD2II_end(h4);
|
||||||
|
for(int i=0;i<16;i++) realkey[i]=h4[i];
|
||||||
|
|
||||||
|
// printf("=== realkey final (16 bytes) ===\n");
|
||||||
|
// print_hex(realkey,16);
|
||||||
|
|
||||||
|
n1global=16;
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(lfsrhexa,4);
|
||||||
|
MD2II_hashing(realkey,16);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
uint8_t input_register[16]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//copy h4 to the input_register for the cipher
|
||||||
|
memcpy(input_register, h4, 16);
|
||||||
|
|
||||||
|
/* --- MD2II with n1global=32 --- */
|
||||||
|
n1global=32;
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(lfsrhexa,4);
|
||||||
|
MD2II_hashing(realkey,16);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
//copy h4 to the tab for the cipher
|
||||||
|
uint8_t tab[16]; memset(tab, 0, sizeof(tab));
|
||||||
|
memcpy(tab, h4, 16);
|
||||||
|
|
||||||
|
// printf("=== Input Register (16 bytes) ===\n");
|
||||||
|
// print_hex(input_register,16);
|
||||||
|
|
||||||
|
// printf("=== Tab (16 bytes) ===\n");
|
||||||
|
// print_hex(tab,16);
|
||||||
|
|
||||||
|
/* --- keystream output --- */
|
||||||
|
uint8_t output[128]; memset(output, 0, sizeof(output));
|
||||||
|
|
||||||
|
//discard round
|
||||||
|
keystream35(input_register, tab);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
keystream35(input_register, tab);
|
||||||
|
memcpy(output+(i*16), input_register, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
//store ks_bytes to storage
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
ks_bytes[i] = 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 < 128; 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/kirisun_files/reinforced-key-9.wav' -H 'C607727B8BECC3CB 7DD174F5526BB546 B3DEA1C111DC1994 69243120CDB6F99A'
|
||||||
|
void kirisun_reinforced_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[128]; 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];
|
||||||
|
|
||||||
|
// printf("=== userkey input (32 bytes) ===\n");
|
||||||
|
// print_hex(userkeyhexa,32);
|
||||||
|
|
||||||
|
/* --- 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);
|
||||||
|
|
||||||
|
n1global=8;
|
||||||
|
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<8;i++)
|
||||||
|
internal_state=(internal_state<<8)+(h4[i]);
|
||||||
|
|
||||||
|
// printf("internal_state=%016llX\n",(unsigned long long)internal_state);
|
||||||
|
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy internal state value to the input_register for the modified DES cipher
|
||||||
|
memcpy(input_register, h4, 8);
|
||||||
|
|
||||||
|
/* --- MD2II with n1global=96 --- */
|
||||||
|
n1global=96;
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(lfsrhexa,4);
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
// printf("realkey (96 bytes):\n");
|
||||||
|
// print_hex(h4,96);
|
||||||
|
|
||||||
|
/* --- keystream output --- */
|
||||||
|
uint8_t output[128]; memset(output, 0, sizeof(output));
|
||||||
|
|
||||||
|
//run discard round first
|
||||||
|
ksun_des_cipher(h4, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//begin creation of actual keystream now
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
//the internal state is the output feedback mode
|
||||||
|
ksun_des_cipher(h4, input_register, output_register, 1);
|
||||||
|
memcpy(output+(i*8), output_register, 8);
|
||||||
|
memcpy(input_register, output_register, 8);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("keystream output (128 bytes):\n");
|
||||||
|
// print_hex(output,128);
|
||||||
|
|
||||||
|
//store ks_bytes to storage
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
ks_bytes[i] = 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 < 128; 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/kirisun_files/strengthened-key-7.wav' -H 'C607727B8BECC3CB 7DD174F5526BB546 B3DEA1C111DC1994 69243120CDB6F99A'
|
||||||
|
void kirisun_strengthened_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[128]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
uint8_t global_key[288]; memset (global_key, 0, sizeof(global_key));
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
// printf("=== userkey input (32 bytes) ===\n");
|
||||||
|
// print_hex(userkeyhexa,32);
|
||||||
|
|
||||||
|
/* --- MD2II first pass --- */
|
||||||
|
n1global=32;
|
||||||
|
unsigned char h4[288]; 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);
|
||||||
|
|
||||||
|
n1global=288;
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(realkey, 32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
for (int i=0;i<288;i++) global_key[i]=h4[i];
|
||||||
|
|
||||||
|
// printf("=== global key (288 bytes) ===\n");
|
||||||
|
// print_hex(realkey,288);
|
||||||
|
|
||||||
|
n1global=8;
|
||||||
|
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<8;i++)
|
||||||
|
internal_state=(internal_state<<8)+(h4[i]);
|
||||||
|
|
||||||
|
// printf("internal_state=%016llX\n",(unsigned long long)internal_state);
|
||||||
|
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy internal state value to the input_register for the modified DES cipher
|
||||||
|
memcpy(input_register, h4, 8);
|
||||||
|
|
||||||
|
/* --- MD2II with n1global=96 --- */
|
||||||
|
n1global=96;
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(lfsrhexa,4);
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
// printf("realkey (96 bytes):\n");
|
||||||
|
// print_hex(h4,96);
|
||||||
|
|
||||||
|
/* --- keystream output --- */
|
||||||
|
uint8_t output[128]; memset(output, 0, sizeof(output));
|
||||||
|
|
||||||
|
//run discard round first
|
||||||
|
ksun_des_cipher(global_key+0, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
ksun_des_cipher(global_key+96, input_register, output_register, 0);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
ksun_des_cipher(global_key+192, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//begin creation of actual keystream now
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
//the internal state is the output feedback mode
|
||||||
|
ksun_des_cipher(global_key+0, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
ksun_des_cipher(global_key+96, input_register, output_register, 0);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
ksun_des_cipher(global_key+192, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, 8); //internal_state = des_reinforced(internal_state, encrypt);
|
||||||
|
|
||||||
|
//copy out last output_register to output
|
||||||
|
memcpy(output+(i*8), output_register, 8);
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("keystream output (128 bytes):\n");
|
||||||
|
// print_hex(output,128);
|
||||||
|
|
||||||
|
//store ks_bytes to storage
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
ks_bytes[i] = 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 < 128; i++)
|
||||||
|
// {
|
||||||
|
// if ((i != 0) && ((i%16)==0))
|
||||||
|
// fprintf (stderr, "\n ");
|
||||||
|
// fprintf (stderr, "%02X ", ks_bytes[i]);
|
||||||
|
// }
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirisun_low_keystream_creation(dsd_state *state)
|
||||||
|
{
|
||||||
|
UNUSED(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirisun_middle_keystream_creation(dsd_state *state)
|
||||||
|
{
|
||||||
|
UNUSED(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirisun_high_keystream_creation(dsd_state *state)
|
||||||
|
{
|
||||||
|
UNUSED(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirisun_top_keystream_creation(dsd_state *state)
|
||||||
|
{
|
||||||
|
UNUSED(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BLOCK_BYTES 512
|
||||||
|
#define MEMORY_BYTES 4608
|
||||||
|
|
||||||
|
static uint8_t memory_area[MEMORY_BYTES];
|
||||||
|
static uint8_t *substitution_area = memory_area;
|
||||||
|
static uint8_t *state_area = memory_area + 2048;
|
||||||
|
static uint8_t *feedback_area = memory_area + 3584;
|
||||||
|
static uint8_t *temporary_area = memory_area + 4096;
|
||||||
|
static size_t processed_bytes;
|
||||||
|
static uint8_t feedback_value;
|
||||||
|
|
||||||
|
static const uint8_t substitution_maps[16][16] = {
|
||||||
|
{ 0x4, 0xA, 0x9, 0x2, 0xD, 0x8, 0x0, 0xE, 0x6, 0xB, 0x1, 0xC, 0x7, 0xF, 0x5, 0x3 },
|
||||||
|
{ 0xE, 0xB, 0x4, 0xC, 0x6, 0xD, 0xF, 0xA, 0x2, 0x3, 0x8, 0x1, 0x0, 0x7, 0x5, 0x9 },
|
||||||
|
{ 0x5, 0x8, 0x1, 0xD, 0xA, 0x3, 0x4, 0x2, 0xE, 0xF, 0xC, 0x7, 0x6, 0x0, 0x9, 0xB },
|
||||||
|
{ 0x7, 0xD, 0xA, 0x1, 0x0, 0x8, 0x9, 0xF, 0xE, 0x4, 0x6, 0xC, 0xB, 0x2, 0x5, 0x3 },
|
||||||
|
{ 0x6, 0xC, 0x7, 0x1, 0x5, 0xF, 0xD, 0x8, 0x4, 0xA, 0x9, 0xE, 0x0, 0x3, 0xB, 0x2 },
|
||||||
|
{ 0x4, 0xB, 0xA, 0x0, 0x7, 0x2, 0x1, 0xD, 0x3, 0x6, 0x8, 0x5, 0x9, 0xC, 0xF, 0xE },
|
||||||
|
{ 0xD, 0xB, 0x4, 0x1, 0x3, 0xF, 0x5, 0x9, 0x0, 0xA, 0xE, 0x7, 0x6, 0x8, 0x2, 0xC },
|
||||||
|
{ 0x1, 0xF, 0xD, 0x0, 0x5, 0x7, 0xA, 0x4, 0x9, 0x2, 0x3, 0xE, 0x6, 0xB, 0x8, 0xC },
|
||||||
|
{ 0xC, 0x4, 0x6, 0x2, 0xA, 0x5, 0xB, 0x9, 0xE, 0x8, 0xD, 0x7, 0x0, 0x3, 0xF, 0x1 },
|
||||||
|
{ 0x6, 0x8, 0x2, 0x3, 0x9, 0xA, 0x5, 0xC, 0x1, 0xE, 0x4, 0x7, 0xB, 0xD, 0x0, 0xF },
|
||||||
|
{ 0xB, 0x3, 0x5, 0x8, 0x2, 0xF, 0xA, 0xD, 0xE, 0x1, 0x7, 0x4, 0xC, 0x9, 0x6, 0x0 },
|
||||||
|
{ 0xC, 0x8, 0x2, 0x1, 0xD, 0x4, 0xF, 0x6, 0x7, 0x0, 0xA, 0x5, 0x3, 0xE, 0x9, 0xB },
|
||||||
|
{ 0x7, 0xF, 0x5, 0xA, 0x8, 0x1, 0x6, 0xD, 0x0, 0x9, 0x3, 0xE, 0xB, 0x4, 0x2, 0xC },
|
||||||
|
{ 0x5, 0xD, 0xF, 0x6, 0x9, 0x2, 0xC, 0xA, 0xB, 0x7, 0x8, 0x1, 0x4, 0x3, 0xE, 0x0 },
|
||||||
|
{ 0x8, 0xE, 0x2, 0x5, 0x6, 0x9, 0x1, 0xC, 0xF, 0x4, 0xB, 0x0, 0xD, 0xA, 0x3, 0x7 },
|
||||||
|
{ 0x1, 0x7, 0xE, 0xD, 0x0, 0x5, 0x8, 0x3, 0x4, 0xF, 0xA, 0x6, 0x9, 0xC, 0xB, 0x2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t nonlinear_map[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};
|
||||||
|
|
||||||
|
|
||||||
|
void prepare_tables(void)
|
||||||
|
{
|
||||||
|
for (unsigned int index = 0; index < 256; ++index) {
|
||||||
|
substitution_area[7 * 256 + index] = (uint8_t)((substitution_maps[15][index >> 4] << 4) | substitution_maps[14][index & 15]);
|
||||||
|
substitution_area[6 * 256 + index] = (uint8_t)((substitution_maps[13][index >> 4] << 4) | substitution_maps[12][index & 15]);
|
||||||
|
substitution_area[5 * 256 + index] = (uint8_t)((substitution_maps[11][index >> 4] << 4) | substitution_maps[10][index & 15]);
|
||||||
|
substitution_area[4 * 256 + index] = (uint8_t)((substitution_maps[9][index >> 4] << 4) | substitution_maps[8][index & 15]);
|
||||||
|
substitution_area[3 * 256 + index] = (uint8_t)((substitution_maps[7][index >> 4] << 4) | substitution_maps[6][index & 15]);
|
||||||
|
substitution_area[2 * 256 + index] = (uint8_t)((substitution_maps[5][index >> 4] << 4) | substitution_maps[4][index & 15]);
|
||||||
|
substitution_area[1 * 256 + index] = (uint8_t)((substitution_maps[3][index >> 4] << 4) | substitution_maps[2][index & 15]);
|
||||||
|
substitution_area[index] = (uint8_t)((substitution_maps[1][index >> 4] << 4) | substitution_maps[0][index & 15]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_state(void)
|
||||||
|
{
|
||||||
|
processed_bytes = 0;
|
||||||
|
feedback_value = 0;
|
||||||
|
memset(feedback_area, 0, 512);
|
||||||
|
memset(state_area, 0, 1536);
|
||||||
|
}
|
||||||
|
|
||||||
|
void md2IIult(const uint8_t input[], size_t length)
|
||||||
|
{
|
||||||
|
size_t input_position = 0;
|
||||||
|
while (length != 0) {
|
||||||
|
for (; length && processed_bytes < BLOCK_BYTES; --length, ++processed_bytes) {
|
||||||
|
uint8_t current_byte = input[input_position++];
|
||||||
|
state_area[processed_bytes + BLOCK_BYTES] = current_byte;
|
||||||
|
state_area[processed_bytes + 2 * BLOCK_BYTES] = (uint8_t)(current_byte ^ state_area[processed_bytes]);
|
||||||
|
feedback_area[processed_bytes] ^= nonlinear_map[current_byte ^ feedback_value];
|
||||||
|
feedback_value = feedback_area[processed_bytes];
|
||||||
|
}
|
||||||
|
if (processed_bytes == BLOCK_BYTES) {
|
||||||
|
unsigned int accumulator = 0;
|
||||||
|
processed_bytes = 0;
|
||||||
|
for (unsigned int round = 0; round < BLOCK_BYTES + 2; ++round) {
|
||||||
|
for (unsigned int index = 0; index < 3 * BLOCK_BYTES; ++index) {
|
||||||
|
state_area[index] ^= nonlinear_map[accumulator];
|
||||||
|
accumulator = state_area[index];
|
||||||
|
}
|
||||||
|
accumulator = (accumulator + round) & 255U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void finalize_state(uint8_t output[BLOCK_BYTES])
|
||||||
|
{
|
||||||
|
size_t remaining_bytes = BLOCK_BYTES - processed_bytes;
|
||||||
|
memset(temporary_area, (int)remaining_bytes, remaining_bytes);
|
||||||
|
md2IIult(temporary_area, remaining_bytes);
|
||||||
|
md2IIult(feedback_area, BLOCK_BYTES);
|
||||||
|
memcpy(output, state_area, BLOCK_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
void derive_schedule(const uint8_t digest[BLOCK_BYTES], uint8_t schedule[BLOCK_BYTES])
|
||||||
|
{
|
||||||
|
size_t digest_position = 0;
|
||||||
|
memset(schedule, 0, BLOCK_BYTES);
|
||||||
|
for (unsigned int block = 0; block < 64; ++block) {
|
||||||
|
uint64_t value = 0;
|
||||||
|
for (unsigned int index = 0; index < 8; ++index) value = (value << 8) | digest[digest_position++];
|
||||||
|
memcpy(schedule + block * 8, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t transform_word(uint64_t value)
|
||||||
|
{
|
||||||
|
uint32_t upper_word = (uint32_t)(value >> 32);
|
||||||
|
uint32_t lower_word = (uint32_t)value;
|
||||||
|
upper_word = ((uint32_t)substitution_area[3 * 256 + ((upper_word >> 24) & 255u)] << 24) |
|
||||||
|
((uint32_t)substitution_area[2 * 256 + ((upper_word >> 16) & 255u)] << 16) |
|
||||||
|
((uint32_t)substitution_area[1 * 256 + ((upper_word >> 8) & 255u)] << 8) |
|
||||||
|
(uint32_t)substitution_area[upper_word & 255u];
|
||||||
|
lower_word = ((uint32_t)substitution_area[7 * 256 + ((lower_word >> 24) & 255u)] << 24) |
|
||||||
|
((uint32_t)substitution_area[6 * 256 + ((lower_word >> 16) & 255u)] << 16) |
|
||||||
|
((uint32_t)substitution_area[5 * 256 + ((lower_word >> 8) & 255u)] << 8) |
|
||||||
|
(uint32_t)substitution_area[4 * 256 + (lower_word & 255u)];
|
||||||
|
value = ((uint64_t)upper_word << 32) | lower_word;
|
||||||
|
return (value << 11) | (value >> (64 - 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
void encode_block(const uint64_t input[2], uint64_t output[2], const uint8_t schedule[BLOCK_BYTES])
|
||||||
|
{
|
||||||
|
uint64_t left_word = input[0], right_word = input[1];
|
||||||
|
for (unsigned int round = 0; round < 32; ++round) {
|
||||||
|
uint64_t round_key;
|
||||||
|
memcpy(&round_key, schedule + round * 16, sizeof(round_key));
|
||||||
|
right_word ^= transform_word(left_word + round_key);
|
||||||
|
memcpy(&round_key, schedule + round * 16 + 8, sizeof(round_key));
|
||||||
|
left_word ^= transform_word(right_word + round_key);
|
||||||
|
}
|
||||||
|
output[0] = right_word;
|
||||||
|
output[1] = left_word;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decode_block(const uint64_t input[2], uint64_t output[2], const uint8_t schedule[BLOCK_BYTES])
|
||||||
|
{
|
||||||
|
uint64_t left_word = input[0], right_word = input[1];
|
||||||
|
for (int round = 31; round >= 0; --round) {
|
||||||
|
uint64_t round_key;
|
||||||
|
memcpy(&round_key, schedule + round * 16 + 8, sizeof(round_key));
|
||||||
|
right_word ^= transform_word(left_word + round_key);
|
||||||
|
memcpy(&round_key, schedule + round * 16, sizeof(round_key));
|
||||||
|
left_word ^= transform_word(right_word + round_key);
|
||||||
|
}
|
||||||
|
output[0] = right_word;
|
||||||
|
output[1] = left_word;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirisun_ultra_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[128]; 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];
|
||||||
|
|
||||||
|
// printf("=== userkey input (32 bytes) ===\n");
|
||||||
|
// print_hex(userkeyhexa,32);
|
||||||
|
|
||||||
|
/* --- 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);
|
||||||
|
|
||||||
|
unsigned char digest[512]; memset(digest, 0, sizeof(digest));
|
||||||
|
unsigned char schedule[512]; memset(schedule, 0, sizeof(schedule));
|
||||||
|
|
||||||
|
prepare_tables();
|
||||||
|
reset_state();
|
||||||
|
md2IIult(realkey, 32);
|
||||||
|
finalize_state(digest);
|
||||||
|
derive_schedule(digest, schedule);
|
||||||
|
|
||||||
|
n1global=32;
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(lfsrhexa,4);
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
// printf("h4[0..7]: ");
|
||||||
|
// print_hex(h4,8);
|
||||||
|
|
||||||
|
//the state machine is comprised of two 64-bit words that
|
||||||
|
//when output become the bytes of the keystream
|
||||||
|
uint64_t internal_state[2]; memset(internal_state, 0, sizeof(internal_state));
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
internal_state[0] <<= 8;
|
||||||
|
internal_state[0] |= (uint64_t)h4[i];
|
||||||
|
|
||||||
|
internal_state[1] <<= 8;
|
||||||
|
internal_state[1] |= (uint64_t)h4[i+8];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- keystream output --- */
|
||||||
|
uint8_t output[128]; memset(output, 0, sizeof(output));
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
encode_block(internal_state, internal_state, schedule);
|
||||||
|
|
||||||
|
output[(i*16)+0] = (internal_state[0] >> 56) & 0xFF;
|
||||||
|
output[(i*16)+1] = (internal_state[0] >> 48) & 0xFF;
|
||||||
|
output[(i*16)+2] = (internal_state[0] >> 40) & 0xFF;
|
||||||
|
output[(i*16)+3] = (internal_state[0] >> 32) & 0xFF;
|
||||||
|
output[(i*16)+4] = (internal_state[0] >> 24) & 0xFF;
|
||||||
|
output[(i*16)+5] = (internal_state[0] >> 16) & 0xFF;
|
||||||
|
output[(i*16)+6] = (internal_state[0] >> 8) & 0xFF;
|
||||||
|
output[(i*16)+7] = (internal_state[0] >> 0) & 0xFF;
|
||||||
|
|
||||||
|
output[(i*16)+8] = (internal_state[1] >> 56) & 0xFF;
|
||||||
|
output[(i*16)+9] = (internal_state[1] >> 48) & 0xFF;
|
||||||
|
output[(i*16)+10] = (internal_state[1] >> 40) & 0xFF;
|
||||||
|
output[(i*16)+11] = (internal_state[1] >> 32) & 0xFF;
|
||||||
|
output[(i*16)+12] = (internal_state[1] >> 24) & 0xFF;
|
||||||
|
output[(i*16)+13] = (internal_state[1] >> 16) & 0xFF;
|
||||||
|
output[(i*16)+14] = (internal_state[1] >> 8) & 0xFF;
|
||||||
|
output[(i*16)+15] = (internal_state[1] >> 0) & 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("keystream output (128 bytes):\n");
|
||||||
|
// print_hex(output,128);
|
||||||
|
|
||||||
|
//store ks_bytes to storage
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
ks_bytes[i] = 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 < 128; i++)
|
||||||
|
// {
|
||||||
|
// if ((i != 0) && ((i%16)==0))
|
||||||
|
// fprintf (stderr, "\n ");
|
||||||
|
// fprintf (stderr, "%02X ", ks_bytes[i]);
|
||||||
|
// }
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//General Keystream Creator for any known Kirisun cipher
|
||||||
|
void kirisun_keystream_creation(dsd_state * state)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t algid = 0;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
algid = state->payload_algid;
|
||||||
|
else algid = state->payload_algidR;
|
||||||
|
|
||||||
|
if (algid == 0x31)
|
||||||
|
kirisun_reinforced_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x32)
|
||||||
|
kirisun_low_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x33)
|
||||||
|
kirisun_middle_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x34)
|
||||||
|
kirisun_high_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x35)
|
||||||
|
kirisun_enhanced_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x36)
|
||||||
|
kirisun_advanced_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x37)
|
||||||
|
kirisun_universal_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x38)
|
||||||
|
kirisun_strengthened_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x39)
|
||||||
|
kirisun_top_keystream_creation(state);
|
||||||
|
|
||||||
|
else if (algid == 0x3A)
|
||||||
|
kirisun_ultra_keystream_creation(state);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
458
src/crypt-md5.c
Normal file
458
src/crypt-md5.c
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
//MD5 Code Originally Sourced From: https://github.com/Zunawe/md5-c
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
|
||||||
|
* and modified slightly to be functionally identical but condensed into control structures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
uint64_t size; // Size of input in bytes
|
||||||
|
uint32_t buffer[4]; // Current accumulation of hash
|
||||||
|
uint8_t input[64]; // Input to be used in the next step
|
||||||
|
uint8_t digest[16]; // Result of algorithm
|
||||||
|
}MD5Context;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants defined by the MD5 algorithm
|
||||||
|
*/
|
||||||
|
#define A 0x67452301
|
||||||
|
#define B 0xefcdab89
|
||||||
|
#define C 0x98badcfe
|
||||||
|
#define D 0x10325476
|
||||||
|
|
||||||
|
static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||||
|
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||||
|
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||||
|
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
|
||||||
|
|
||||||
|
static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||||
|
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||||
|
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||||
|
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||||
|
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||||
|
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||||
|
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||||
|
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||||
|
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||||
|
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||||
|
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||||
|
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||||
|
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||||
|
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||||
|
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||||
|
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Padding used to make the size (in bits) of the input congruent to 448 mod 512
|
||||||
|
*/
|
||||||
|
static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit-manipulation functions defined by the MD5 algorithm
|
||||||
|
*/
|
||||||
|
#define F(X, Y, Z) ((X & Y) | (~X & Z))
|
||||||
|
#define G(X, Y, Z) ((X & Z) | (Y & ~Z))
|
||||||
|
#define H(X, Y, Z) (X ^ Y ^ Z)
|
||||||
|
#define I(X, Y, Z) (Y ^ (X | ~Z))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotates a 32-bit word left by n bits
|
||||||
|
*/
|
||||||
|
uint32_t rotateLeft(uint32_t x, uint32_t n){
|
||||||
|
return (x << n) | (x >> (32 - n));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a context
|
||||||
|
*/
|
||||||
|
void md5Init(MD5Context *ctx){
|
||||||
|
ctx->size = (uint64_t)0;
|
||||||
|
|
||||||
|
ctx->buffer[0] = (uint32_t)A;
|
||||||
|
ctx->buffer[1] = (uint32_t)B;
|
||||||
|
ctx->buffer[2] = (uint32_t)C;
|
||||||
|
ctx->buffer[3] = (uint32_t)D;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Step on 512 bits of input with the main MD5 algorithm.
|
||||||
|
*/
|
||||||
|
void md5Step(uint32_t *buffer, uint32_t *input){
|
||||||
|
uint32_t AA = buffer[0];
|
||||||
|
uint32_t BB = buffer[1];
|
||||||
|
uint32_t CC = buffer[2];
|
||||||
|
uint32_t DD = buffer[3];
|
||||||
|
|
||||||
|
uint32_t E;
|
||||||
|
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < 64; ++i){
|
||||||
|
switch(i / 16){
|
||||||
|
case 0:
|
||||||
|
E = F(BB, CC, DD);
|
||||||
|
j = i;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
E = G(BB, CC, DD);
|
||||||
|
j = ((i * 5) + 1) % 16;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
E = H(BB, CC, DD);
|
||||||
|
j = ((i * 3) + 5) % 16;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
E = I(BB, CC, DD);
|
||||||
|
j = (i * 7) % 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t temp = DD;
|
||||||
|
DD = CC;
|
||||||
|
CC = BB;
|
||||||
|
BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]);
|
||||||
|
AA = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[0] += AA;
|
||||||
|
buffer[1] += BB;
|
||||||
|
buffer[2] += CC;
|
||||||
|
buffer[3] += DD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add some amount of input to the context
|
||||||
|
*
|
||||||
|
* If the input fills out a block of 512 bits, apply the algorithm (md5Step)
|
||||||
|
* and save the result in the buffer. Also updates the overall size.
|
||||||
|
*/
|
||||||
|
void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){
|
||||||
|
uint32_t input[16];
|
||||||
|
unsigned int offset = ctx->size % 64;
|
||||||
|
ctx->size += (uint64_t)input_len;
|
||||||
|
|
||||||
|
// Copy each byte in input_buffer into the next space in our context input
|
||||||
|
for(unsigned int i = 0; i < input_len; ++i){
|
||||||
|
ctx->input[offset++] = (uint8_t)*(input_buffer + i);
|
||||||
|
|
||||||
|
// If we've filled our context input, copy it into our local array input
|
||||||
|
// then reset the offset to 0 and fill in a new buffer.
|
||||||
|
// Every time we fill out a chunk, we run it through the algorithm
|
||||||
|
// to enable some back and forth between cpu and i/o
|
||||||
|
if(offset % 64 == 0){
|
||||||
|
for(unsigned int j = 0; j < 16; ++j){
|
||||||
|
// Convert to little-endian
|
||||||
|
// The local variable `input` our 512-bit chunk separated into 32-bit words
|
||||||
|
// we can use in calculations
|
||||||
|
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
|
||||||
|
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
|
||||||
|
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
|
||||||
|
(uint32_t)(ctx->input[(j * 4)]);
|
||||||
|
}
|
||||||
|
md5Step(ctx->buffer, input);
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pad the current input to get to 448 bytes, append the size in bits to the very end,
|
||||||
|
* and save the result of the final iteration into digest.
|
||||||
|
*/
|
||||||
|
void md5Finalize(MD5Context *ctx){
|
||||||
|
uint32_t input[16];
|
||||||
|
unsigned int offset = ctx->size % 64;
|
||||||
|
unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;
|
||||||
|
|
||||||
|
// Fill in the padding and undo the changes to size that resulted from the update
|
||||||
|
md5Update(ctx, PADDING, padding_length);
|
||||||
|
ctx->size -= (uint64_t)padding_length;
|
||||||
|
|
||||||
|
// Do a final update (internal to this function)
|
||||||
|
// Last two 32-bit words are the two halves of the size (converted from bytes to bits)
|
||||||
|
for(unsigned int j = 0; j < 14; ++j){
|
||||||
|
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
|
||||||
|
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
|
||||||
|
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
|
||||||
|
(uint32_t)(ctx->input[(j * 4)]);
|
||||||
|
}
|
||||||
|
input[14] = (uint32_t)(ctx->size * 8);
|
||||||
|
input[15] = (uint32_t)((ctx->size * 8) >> 32);
|
||||||
|
|
||||||
|
md5Step(ctx->buffer, input);
|
||||||
|
|
||||||
|
// Move the result into digest (convert from little-endian)
|
||||||
|
for(unsigned int i = 0; i < 4; ++i){
|
||||||
|
ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF));
|
||||||
|
ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8);
|
||||||
|
ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16);
|
||||||
|
ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions that run the algorithm on the provided input and put the digest into result.
|
||||||
|
* result should be able to store 16 bytes.
|
||||||
|
*/
|
||||||
|
void md5String(char *input, uint8_t *result){
|
||||||
|
MD5Context ctx;
|
||||||
|
md5Init(&ctx);
|
||||||
|
md5Update(&ctx, (uint8_t *)input, strlen(input));
|
||||||
|
md5Finalize(&ctx);
|
||||||
|
|
||||||
|
memcpy(result, ctx.digest, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void md5File(FILE *file, uint8_t *result){
|
||||||
|
char *input_buffer = malloc(1024);
|
||||||
|
size_t input_size = 0;
|
||||||
|
|
||||||
|
MD5Context ctx;
|
||||||
|
md5Init(&ctx);
|
||||||
|
|
||||||
|
while((input_size = fread(input_buffer, 1, 1024, file)) > 0){
|
||||||
|
md5Update(&ctx, (uint8_t *)input_buffer, input_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
md5Finalize(&ctx);
|
||||||
|
|
||||||
|
free(input_buffer);
|
||||||
|
|
||||||
|
memcpy(result, ctx.digest, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RAS 104-bit permutation
|
||||||
|
*
|
||||||
|
* Generates a permutation of bit positions 0..103 using the 32-bit seed
|
||||||
|
* (the last four active key bytes interpreted as a big-endian uint32).
|
||||||
|
*
|
||||||
|
* Algorithm:
|
||||||
|
* - Maintain a circular list of the still-available positions.
|
||||||
|
* - Repeatedly select (seed % remaining_count) steps from the current
|
||||||
|
* position, record that index, remove it, and continue from its successor.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* seed - 32-bit seed (e.g. 0x92604BD5)
|
||||||
|
* order - output array of 104 integers. order[i] = source bit position
|
||||||
|
* that should be placed at output bit i.
|
||||||
|
*/
|
||||||
|
void ras_permute_order(uint32_t seed, int * order)
|
||||||
|
{
|
||||||
|
int remaining[104];
|
||||||
|
int count = 104;
|
||||||
|
int pos = 0; /* current index inside the remaining[] array */
|
||||||
|
|
||||||
|
for (int i = 0; i < 104; i++)
|
||||||
|
remaining[i] = i;
|
||||||
|
|
||||||
|
for (int i = 0; i < 104; i++)
|
||||||
|
{
|
||||||
|
unsigned idx = seed % (unsigned)count;
|
||||||
|
int actual = (pos + (int)idx) % count;
|
||||||
|
|
||||||
|
order[i] = remaining[actual];
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\n I: %d; C: %d; P: %d; IDX: %u; ACT: %d; ORD: %d; ", i, count, pos, idx, actual, order[i]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* remove the chosen entry */
|
||||||
|
for (int j = actual; j < count - 1; j++)
|
||||||
|
remaining[j] = remaining[j + 1];
|
||||||
|
count--;
|
||||||
|
|
||||||
|
/* continue from the successor of the removed element */
|
||||||
|
if (count > 0)
|
||||||
|
pos = actual % count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
//debug
|
||||||
|
// fprintf(stderr, "\n Order: ");
|
||||||
|
// for (int i = 0; i < 104; i++)
|
||||||
|
// fprintf (stderr, "%03d,", order[i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_ras_permutation(const uint8_t * src, uint8_t * dst, const int * order)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 104; i++)
|
||||||
|
{
|
||||||
|
int src_bit = order[i];
|
||||||
|
int src_byte = src_bit / 8;
|
||||||
|
int src_off = 7 - (src_bit % 8); /* MSB of byte is lowest bit index */
|
||||||
|
|
||||||
|
int bit = (src[src_byte] >> src_off) & 1;
|
||||||
|
|
||||||
|
int dst_byte = i / 8;
|
||||||
|
int dst_off = 7 - (i % 8);
|
||||||
|
|
||||||
|
if (bit)
|
||||||
|
dst[dst_byte] |= (uint8_t)(1u << dst_off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Full RAS workflow, return value is the the calculated MAC attachment
|
||||||
|
//input is a pointer to byte-wise payload from dburst of RAS enabled payloads
|
||||||
|
uint32_t ras_mac_calculator(dsd_state * state, uint8_t * input, int input_len, int type)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (state->ras_effective_key == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t mac = 0;
|
||||||
|
uint8_t ras_input[13];
|
||||||
|
memset (ras_input, 0, sizeof(ras_input));
|
||||||
|
|
||||||
|
for (int i = 0; i < input_len; i++)
|
||||||
|
ras_input[i] = input[i];
|
||||||
|
|
||||||
|
int shift = 48;
|
||||||
|
for (int i = input_len; i < 13; i++)
|
||||||
|
{
|
||||||
|
ras_input[i] = (state->ras_effective_key >> shift) & 0xFF;
|
||||||
|
shift -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
//debug input value
|
||||||
|
if (type != 2)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n RAS Input: ");
|
||||||
|
for (int i = 0; i < 13; i++)
|
||||||
|
fprintf (stderr, "%02X", ras_input[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t ras_output[16]; memset(ras_output, 0, sizeof(ras_output));
|
||||||
|
|
||||||
|
if (type != 2)
|
||||||
|
{
|
||||||
|
apply_ras_permutation(ras_input, ras_output, state->ras_permutation_order);
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
//debug output value
|
||||||
|
fprintf (stderr, "\n RAS Output: ");
|
||||||
|
for (int i = 0; i < 13; i++)
|
||||||
|
fprintf (stderr, "%02X", ras_output[i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//Run Appropriate CRC or RS calculation on Permuted Output
|
||||||
|
uint8_t output_bits[104]; memset(output_bits, 0, sizeof(output_bits));
|
||||||
|
unpack_byte_array_into_bit_array(ras_output, output_bits, 13);
|
||||||
|
|
||||||
|
if (type == 0)
|
||||||
|
mac = ComputeCrcCCITT16d(output_bits, 13*8);
|
||||||
|
else if (type == 1)
|
||||||
|
{
|
||||||
|
rs_16_13_encode(ras_output);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
mac <<= 8;
|
||||||
|
mac |= ras_output[i+13];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == 2)
|
||||||
|
{
|
||||||
|
mac = ComputeCrc5Bit(input);
|
||||||
|
mac += state->ras_effective_key & 0x1F;
|
||||||
|
mac %= 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mac;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ras_effective_key_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t md5_key[30];
|
||||||
|
memset (md5_key, 0, sizeof(md5_key));
|
||||||
|
|
||||||
|
uint16_t len = strlen((const char*)input);
|
||||||
|
|
||||||
|
//sanity check on provided char len
|
||||||
|
if (len > 24)
|
||||||
|
len = 24;
|
||||||
|
|
||||||
|
//load chars as uint8_t into key array
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
md5_key[i] = (uint8_t)input[i];
|
||||||
|
|
||||||
|
//debug
|
||||||
|
fprintf (stderr, "RAS Key String: %s; LEN: %d; HEX: ", input, len);
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
fprintf (stderr, "%02X ", md5_key[i]);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
MD5Context ctx;
|
||||||
|
md5Init(&ctx);
|
||||||
|
md5Update(&ctx, md5_key, len);
|
||||||
|
md5Finalize(&ctx);
|
||||||
|
|
||||||
|
//debug dump the digest
|
||||||
|
fprintf (stderr, "MD5: ");
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
fprintf (stderr, "%02X ", ctx.digest[i]);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
//collect 7 bytes of the MD5 Hash to create the flat key value
|
||||||
|
unsigned long long int flat_key = 0;
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
flat_key <<= 8;
|
||||||
|
flat_key |= ctx.digest[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//On real world testing, it was discovered that by selecting a password (VluByDZhkPenguinkeeper) which has
|
||||||
|
//an MD5 partial hash of FFFFFFFFFEDFFF, the value actually placed into the radio was FFFFFFFFFEE001
|
||||||
|
//this indicates the entire value will roll-over, and not just a byte rollvoer (mod)
|
||||||
|
|
||||||
|
//The known rule is that the last 5 bits of the flat key value (prior to reverse)
|
||||||
|
//is that it cannot equal 0x1F (all 1 bits), if so, a correction of +2 is
|
||||||
|
//performaed onto a flat value, which increments the entire value appropriately
|
||||||
|
|
||||||
|
//Below patent also suggest all bytes cannot equal zero
|
||||||
|
//and if so, the next portion of MD5 may be used,
|
||||||
|
//or some other method may be utilized to prevent fringe cases
|
||||||
|
//https://patents.google.com/patent/US20130288643A1
|
||||||
|
|
||||||
|
if ((flat_key & 0x1F) == 0x1F)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Flat Correction: %014llX -> %014llX;\n", flat_key, flat_key+2);
|
||||||
|
flat_key += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//byte-reverse the flat_key into the effective_key
|
||||||
|
unsigned long long int effective_key = 0;
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
effective_key <<= 8;
|
||||||
|
effective_key |= (flat_key >> (i*8)) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ras_seed = effective_key & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
ras_permute_order(ras_seed, state->ras_permutation_order);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
fprintf (stderr, "RAS Effective Key Value: %014llX;", effective_key);
|
||||||
|
|
||||||
|
state->ras_effective_key = effective_key;
|
||||||
|
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
1376
src/crypt-rc4.c
1376
src/crypt-rc4.c
File diff suppressed because it is too large
Load Diff
@@ -307,55 +307,3 @@ void tyt_ep_aes_keystream_creation(dsd_state * state, char * input)
|
|||||||
state->tyt_ep = 1;
|
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
150
src/dmr_block.c
150
src/dmr_block.c
@@ -187,6 +187,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera");
|
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera");
|
||||||
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera");
|
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera");
|
||||||
else if (p_mfid == 0x06) sprintf (mfid_string, "%s", "Trid/Mot");
|
else if (p_mfid == 0x06) sprintf (mfid_string, "%s", "Trid/Mot");
|
||||||
|
else if (p_mfid == 0x77) sprintf (mfid_string, "%s", "VTX STD");
|
||||||
else if (p_mfid == 0x00) sprintf (mfid_string, "%s", "Standard");
|
else if (p_mfid == 0x00) sprintf (mfid_string, "%s", "Standard");
|
||||||
else sprintf (mfid_string, "%s", "Other");
|
else sprintf (mfid_string, "%s", "Other");
|
||||||
}
|
}
|
||||||
@@ -378,38 +379,77 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
if (p_sap != 1 && p_mfid == 0x77)
|
if (p_sap != 1 && p_mfid == 0x77)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf (stderr, "\n Vertex Standard PDU ENC Header:");
|
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
|
//This Extended Header only seems to exist to signal encryption,
|
||||||
//guess work and best judgment from single sample of Vertex Enhanced
|
//but is otherwise mostly empty aside from a FID and single 0x01 value
|
||||||
|
//[4F][77][01][00][00][00][00][00][00][00][XX][XX]
|
||||||
|
|
||||||
//main issue is, I don't know if the 0x01 signalled is a key id (which is known to be 0x01)
|
//Further analysis shows that using different key types on different channels
|
||||||
//or if it is an encryption alg id (alg may have to be inferred based on what is loaded in radio)
|
//does not change the byte values of this header, and what is reported is that
|
||||||
|
//the Vertex Standard radios only allow one encryption type and key per channel.
|
||||||
|
|
||||||
//set to 0x100 so it won't trigger any weird flags, but still has a non-zero value to be checked later
|
//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;
|
if (state->currentslot == 0) state->dmr_so = 0x100;
|
||||||
else state->dmr_soR = 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
|
//going to use algid of 0x7 to signal a vertex standard enc method
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
state->payload_algid = 0x7;
|
state->payload_algid = 0x7;
|
||||||
else state->payload_algidR = 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
|
//reset ks start value
|
||||||
state->data_ks_start[slot] = 0;
|
state->data_ks_start[slot] = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (p_sap != 1 && p_mfid == 0x68)
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO: Assume Alg, Key ID, IV and other values present in this header
|
||||||
|
//if using Hytera Enhanced RC4, otherwise, may use DMRA header
|
||||||
|
//ALG 1 = BP (observed), ALG 2 = Hytera Enhanced (not observed, but speculation)
|
||||||
|
|
||||||
|
/*
|
||||||
|
15:44:00 Sync: +DMR MS/DM MODE/MONO | Color Code=01 | DATA
|
||||||
|
Slot 1 Data Header - Extended - SAP 03 [UDP Comp] - MFID 68 [Hytera]
|
||||||
|
Unknown Extended Header: 0101000000000000
|
||||||
|
DMR PDU Payload [3F][68][01][01][00][00][00][00][00][00][E6][71] <-- key 1
|
||||||
|
|
||||||
|
16:06:21 Sync: +DMR MS/DM MODE/MONO | Color Code=02 | DATA
|
||||||
|
Slot 1 Data Header - Extended - SAP 03 [UDP Comp] - MFID 68 [Hytera]
|
||||||
|
Hytera PDU ENC Header;
|
||||||
|
DMR PDU Payload [3F][68][01][02][00][00][00][00][00][00][3E][F3] <--key 2
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint8_t alg = (uint8_t)ConvertBitIntoBytes(&dheader_bits[16], 8);
|
||||||
|
uint8_t key = (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8);
|
||||||
|
uint64_t mi = (uint64_t)ConvertBitIntoBytes(&dheader_bits[32], 40);
|
||||||
|
|
||||||
|
fprintf (stderr, "\n Hytera PDU ENC Header: MFID: %02X; ALG: %02X; Key ID: %02X;", p_mfid, alg, key);
|
||||||
|
if (mi != 0) fprintf (stderr, "MI: %010llX", (unsigned long long int)mi);
|
||||||
|
|
||||||
|
//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;
|
||||||
|
|
||||||
|
//going to use algid of 0x68*alg to signal a Hytera enc method
|
||||||
|
//should be 0x68 for bp, or 0xD0 for enhanced
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
state->payload_algid = 0x68 * alg;
|
||||||
|
else state->payload_algidR = 0x68 * alg;
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
state->payload_keyid = key;
|
||||||
|
else state->payload_keyidR = key;
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
state->payload_mi = mi;
|
||||||
|
else state->payload_miR = mi;
|
||||||
|
|
||||||
|
//reset ks start value
|
||||||
|
state->data_ks_start[slot] = 0;
|
||||||
|
}
|
||||||
else if (p_sap != 1 && p_mfid == 0x10)
|
else if (p_sap != 1 && p_mfid == 0x10)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1047,11 +1087,11 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
kaes[i+8] = ((state->rkey_array[kid+0x101]) >> (56-(i*8))) & 0xFF;
|
kaes[i+8] = ((state->rkey_array[kid+0x101]) >> (56-(i*8))) & 0xFF;
|
||||||
kaes[i+16] = ((state->rkey_array[kid+0x201]) >> (56-(i*8))) & 0xFF;
|
kaes[i+16] = ((state->rkey_array[kid+0x201]) >> (56-(i*8))) & 0xFF;
|
||||||
kaes[i+24] = ((state->rkey_array[kid+0x301]) >> (56-(i*8))) & 0xFF;
|
kaes[i+24] = ((state->rkey_array[kid+0x301]) >> (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 kaes is loaded with a key, then flag on the key loaded variable
|
||||||
|
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 still not akl, see if there is anything manually loaded into K1, K2, K3, K4 instead
|
||||||
if (akl == 0)
|
if (akl == 0)
|
||||||
{
|
{
|
||||||
@@ -1089,6 +1129,8 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
if (alg == 4) fprintf (stderr, " AES128;");
|
if (alg == 4) fprintf (stderr, " AES128;");
|
||||||
if (alg == 5) fprintf (stderr, " AES256;");
|
if (alg == 5) fprintf (stderr, " AES256;");
|
||||||
if (alg == 7) fprintf (stderr, " VTX STD;");
|
if (alg == 7) fprintf (stderr, " VTX STD;");
|
||||||
|
if (alg == 0x68) fprintf (stderr, " Hytera BP;");
|
||||||
|
if (alg == 0xD0) fprintf (stderr, " Hytera EP;");
|
||||||
if (R && alg != 0) fprintf (stderr, " Key: %010llX;", R);
|
if (R && alg != 0) fprintf (stderr, " Key: %010llX;", R);
|
||||||
|
|
||||||
//generate 128-bit IV from 32-bit MI
|
//generate 128-bit IV from 32-bit MI
|
||||||
@@ -1115,6 +1157,65 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
decrypted_pdu = 1;
|
decrypted_pdu = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (alg == 0x68) //Hytera BP
|
||||||
|
{
|
||||||
|
//just passing through to see if a key was loaded and the blocks decrypted
|
||||||
|
decrypted_pdu = hytera_bp_data_decrypt(state, empt, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (alg == 0xD0) //Hytera Enhanced RC4
|
||||||
|
{
|
||||||
|
//just passing through to see if a key was loaded and the blocks decrypted
|
||||||
|
decrypted_pdu = hytera_ep_data_decrypt(opts, state, empt, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (alg == 7 && state->vtx_key_loaded == 1) //Vertex Standard, either enc type
|
||||||
|
{
|
||||||
|
pack_bit_array_into_byte_array(state->static_ks_bits[slot], ob, 8);
|
||||||
|
end += (poc + 4); //also perform application over padding bytes and crc value
|
||||||
|
for (i = 0; i < end; i++)
|
||||||
|
state->dmr_pdu_sf[slot][i+start] ^= ob[i%8];
|
||||||
|
decrypted_pdu = 1;
|
||||||
|
|
||||||
|
//Recalcuate CRC32
|
||||||
|
uint8_t reordered_bits[1000];
|
||||||
|
memset (reordered_bits, 0, sizeof(reordered_bits));
|
||||||
|
|
||||||
|
//rearrage for ridiculously stupid CRC32 LSO/MSO ordering
|
||||||
|
for(i = 0, j = 0; i < ctr; i+=2, j+=16)
|
||||||
|
{
|
||||||
|
reordered_bits[j + 0] = (state->dmr_pdu_sf[slot][i+1] >> 7) & 0x01;
|
||||||
|
reordered_bits[j + 1] = (state->dmr_pdu_sf[slot][i+1] >> 6) & 0x01;
|
||||||
|
reordered_bits[j + 2] = (state->dmr_pdu_sf[slot][i+1] >> 5) & 0x01;
|
||||||
|
reordered_bits[j + 3] = (state->dmr_pdu_sf[slot][i+1] >> 4) & 0x01;
|
||||||
|
reordered_bits[j + 4] = (state->dmr_pdu_sf[slot][i+1] >> 3) & 0x01;
|
||||||
|
reordered_bits[j + 5] = (state->dmr_pdu_sf[slot][i+1] >> 2) & 0x01;
|
||||||
|
reordered_bits[j + 6] = (state->dmr_pdu_sf[slot][i+1] >> 1) & 0x01;
|
||||||
|
reordered_bits[j + 7] = (state->dmr_pdu_sf[slot][i+1] >> 0) & 0x01;
|
||||||
|
|
||||||
|
reordered_bits[j + 8] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
|
||||||
|
reordered_bits[j + 9] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
|
||||||
|
reordered_bits[j + 10] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
|
||||||
|
reordered_bits[j + 11] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
|
||||||
|
reordered_bits[j + 12] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
|
||||||
|
reordered_bits[j + 13] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
|
||||||
|
reordered_bits[j + 14] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
|
||||||
|
reordered_bits[j + 15] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
|
||||||
|
}
|
||||||
|
CRCComputed = (uint32_t)ComputeCrc32BitV(reordered_bits, (ctr * 8) - 32);
|
||||||
|
CRCExtracted = (uint32_t)convert_bits_into_output(reordered_bits+((ctr * 8) - 32), 32);
|
||||||
|
if (CRCComputed == CRCExtracted)
|
||||||
|
CRCCorrect = 1;
|
||||||
|
else CRCCorrect = 0;
|
||||||
|
|
||||||
|
//set back to original value
|
||||||
|
end -= (poc + 4);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " CTR: %d; CRC32 CMP: %08X EXT: %08X", ctr, CRCComputed, CRCExtracted);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
else if (alg == 5 && akl == 1 && mi != 0) //AES-256 OFB
|
else if (alg == 5 && akl == 1 && mi != 0) //AES-256 OFB
|
||||||
{
|
{
|
||||||
int nblocks = (state->data_byte_ctr[slot] / 16) + 1;
|
int nblocks = (state->data_byte_ctr[slot] / 16) + 1;
|
||||||
@@ -1266,7 +1367,8 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
}
|
}
|
||||||
else if (state->data_header_sap[slot] == 2 || state->data_header_sap[slot] == 3) //TCP and UDP Compression (may only be 3 UDP compression, unknown)
|
else if (state->data_header_sap[slot] == 2 || state->data_header_sap[slot] == 3) //TCP and UDP Compression (may only be 3 UDP compression, unknown)
|
||||||
{
|
{
|
||||||
uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes
|
uint8_t poc = state->data_block_poc[slot]; //need to test if others also need this
|
||||||
|
uint16_t len = ((blocks+1)*block_len)-4 - poc; //total number of bytes in PDU minus 4 CRC32 bytes and padding bytes
|
||||||
dmr_udp_comp_pdu (opts, state, len, state->dmr_pdu_sf[slot]);
|
dmr_udp_comp_pdu (opts, state, len, state->dmr_pdu_sf[slot]);
|
||||||
}
|
}
|
||||||
else if (state->data_header_sap[slot] == 1 && state->dmr_pdu_sf[slot][1] == 0x10) //MNIS Proprietary Header
|
else if (state->data_header_sap[slot] == 1 && state->dmr_pdu_sf[slot][1] == 0x10) //MNIS Proprietary Header
|
||||||
@@ -1604,4 +1706,12 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
|||||||
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||||
sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
||||||
sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
memset(state->hota_lc_ctx, 0, sizeof(state->hota_lc_ctx));
|
||||||
|
memset(state->hota_ctx_ok, 0, sizeof(state->hota_ctx_ok));
|
||||||
|
state->hota_sbrc_idx1[0] = -1;
|
||||||
|
state->hota_sbrc_idx2[0] = -1;
|
||||||
|
state->hota_sbrc_idx1[1] = -1;
|
||||||
|
state->hota_sbrc_idx2[1] = -1;
|
||||||
}
|
}
|
||||||
26
src/dmr_bs.c
26
src/dmr_bs.c
@@ -462,6 +462,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (internalslot == 0 && vc1 == 6)
|
if (internalslot == 0 && vc1 == 6)
|
||||||
{
|
{
|
||||||
|
if (state->hota_enc_check && state->forced_alg_id > 1)
|
||||||
|
{
|
||||||
|
state->dmr_so = 0x40;
|
||||||
|
state->payload_algid = state->forced_alg_id;
|
||||||
|
state->payload_keyid = 0xFF;
|
||||||
|
}
|
||||||
//this needs to run prior to embedded link control
|
//this needs to run prior to embedded link control
|
||||||
if (state->payload_algid == 0x02)
|
if (state->payload_algid == 0x02)
|
||||||
hytera_enhanced_alg_refresh(state);
|
hytera_enhanced_alg_refresh(state);
|
||||||
@@ -475,6 +481,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (internalslot == 1 && vc2 == 6)
|
if (internalslot == 1 && vc2 == 6)
|
||||||
{
|
{
|
||||||
|
if (state->hota_enc_check && state->forced_alg_id > 1)
|
||||||
|
{
|
||||||
|
state->dmr_soR = 0x40;
|
||||||
|
state->payload_algidR = state->forced_alg_id;
|
||||||
|
state->payload_keyidR = 0xFF;
|
||||||
|
}
|
||||||
//this needs to run prior to embedded link control
|
//this needs to run prior to embedded link control
|
||||||
if (state->payload_algidR == 0x02)
|
if (state->payload_algidR == 0x02)
|
||||||
hytera_enhanced_alg_refresh(state);
|
hytera_enhanced_alg_refresh(state);
|
||||||
@@ -509,6 +521,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->vtx256_ekey != 0)
|
||||||
|
{
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr2);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PRINT_AMBE72
|
#ifdef PRINT_AMBE72
|
||||||
ambe2_codeword_print_i(opts, ambe_fr);
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
@@ -968,6 +987,13 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->vtx256_ekey != 0)
|
||||||
|
{
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr2);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PRINT_AMBE72
|
#ifdef PRINT_AMBE72
|
||||||
ambe2_codeword_print_i(opts, ambe_fr);
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
|
|||||||
@@ -940,14 +940,21 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//MassReg
|
//MassReg
|
||||||
if (a_type == 4)
|
if (a_type == 4)
|
||||||
{
|
{
|
||||||
|
uint8_t mreg_res = (uint8_t)ConvertBitIntoBytes(&bpbits1[0], 5);
|
||||||
uint8_t reg_window = (uint8_t)ConvertBitIntoBytes(&bpbits1[5], 4); //7.2.19.5.1 Table 7.77 convert raw to seconds
|
uint8_t reg_window = (uint8_t)ConvertBitIntoBytes(&bpbits1[5], 4); //7.2.19.5.1 Table 7.77 convert raw to seconds
|
||||||
uint8_t aloha_mask = (uint8_t)ConvertBitIntoBytes(&bpbits1[9], 5);
|
uint8_t aloha_mask = (uint8_t)ConvertBitIntoBytes(&bpbits1[9], 5);
|
||||||
|
|
||||||
//ADDRNull or MS Individual Address
|
//ADDRNull or MS Individual Address
|
||||||
uint8_t reg_address = (uint8_t)ConvertBitIntoBytes(&bpbits2[16], 8); //see clause 7.2.41
|
uint32_t reg_address = bparms2; //see clause 7.2.41
|
||||||
|
|
||||||
fprintf (stderr, "\n"); //raw value only on the reg window, see aforementioned table
|
fprintf (stderr, "\n"); //raw value only on the reg window, see aforementioned table
|
||||||
fprintf (stderr, " Reg Window: %X; Aloha Mask: %02X; Target: %d; ", reg_window, aloha_mask, reg_address);
|
fprintf (stderr, " Reg Window: %X; Aloha Mask: %02X; Target: %d; ", reg_window, aloha_mask, reg_address);
|
||||||
dmr_gateway_identifier(0,reg_address);
|
|
||||||
|
if (mreg_res != 0)
|
||||||
|
fprintf (stderr, "Res: %02X", mreg_res);
|
||||||
|
|
||||||
|
if (reg_address != 0)
|
||||||
|
dmr_gateway_identifier(0, reg_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug
|
//debug
|
||||||
|
|||||||
219
src/dmr_dburst.c
219
src/dmr_dburst.c
@@ -6,7 +6,7 @@
|
|||||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
||||||
*
|
*
|
||||||
* LWVMOBILE
|
* LWVMOBILE
|
||||||
* 2023-12 DSD-FME Florida Man Edition
|
* 2026-09 DSD-FME Florida Man Edition
|
||||||
*-----------------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
|
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
|
||||||
@@ -51,14 +51,15 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
//PDU Bytes and Bits
|
//PDU Bytes and Bits
|
||||||
uint8_t DMR_PDU[25];
|
uint8_t DMR_PDU[25];
|
||||||
uint8_t DMR_PDU_bits[196];
|
uint8_t DMR_PDU_bits[200];
|
||||||
memset (DMR_PDU, 0, sizeof (DMR_PDU));
|
memset (DMR_PDU, 0, sizeof (DMR_PDU));
|
||||||
memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits));
|
memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits));
|
||||||
|
|
||||||
uint8_t R[3];
|
uint8_t hota_enc = 0;
|
||||||
uint8_t BPTCReservedBits = 0;
|
uint8_t is_ras = 0;
|
||||||
uint8_t is_ras = 0;
|
uint8_t bptc_res_bits[3];
|
||||||
uint8_t crc_original_validity = 0;
|
memset (bptc_res_bits, 0, sizeof(bptc_res_bits));
|
||||||
|
uint8_t crc_original_validity = 0;
|
||||||
|
|
||||||
uint32_t crcmask = 0;
|
uint32_t crcmask = 0;
|
||||||
uint8_t crclen = 0;
|
uint8_t crclen = 0;
|
||||||
@@ -76,6 +77,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
switch(databurst){
|
switch(databurst){
|
||||||
case 0x00: //PI
|
case 0x00: //PI
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
crclen = 16;
|
crclen = 16;
|
||||||
crcmask = 0x6969; //insert pi and 69 jokes here
|
crcmask = 0x6969; //insert pi and 69 jokes here
|
||||||
@@ -83,6 +85,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
sprintf(state->fsubtype, " PI ");
|
sprintf(state->fsubtype, " PI ");
|
||||||
break;
|
break;
|
||||||
case 0x01: //VLC
|
case 0x01: //VLC
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
is_lc = 1;
|
is_lc = 1;
|
||||||
crclen = 24;
|
crclen = 24;
|
||||||
@@ -91,6 +94,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
sprintf(state->fsubtype, " VLC ");
|
sprintf(state->fsubtype, " VLC ");
|
||||||
break;
|
break;
|
||||||
case 0x02: //TLC
|
case 0x02: //TLC
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
is_lc = 1;
|
is_lc = 1;
|
||||||
crcmask = 0x999999;
|
crcmask = 0x999999;
|
||||||
@@ -99,6 +103,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
sprintf(state->fsubtype, " TLC ");
|
sprintf(state->fsubtype, " TLC ");
|
||||||
break;
|
break;
|
||||||
case 0x03: //CSBK
|
case 0x03: //CSBK
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
crclen = 16;
|
crclen = 16;
|
||||||
crcmask = 0xA5A5;
|
crcmask = 0xA5A5;
|
||||||
@@ -106,6 +111,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
sprintf(state->fsubtype, " CSBK");
|
sprintf(state->fsubtype, " CSBK");
|
||||||
break;
|
break;
|
||||||
case 0x04: //MBC Header
|
case 0x04: //MBC Header
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
crclen = 16;
|
crclen = 16;
|
||||||
crcmask = 0xAAAA;
|
crcmask = 0xAAAA;
|
||||||
@@ -119,6 +125,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
sprintf(state->fsubtype, " MBCC");
|
sprintf(state->fsubtype, " MBCC");
|
||||||
break;
|
break;
|
||||||
case 0x06: //Data Header
|
case 0x06: //Data Header
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
crclen = 16;
|
crclen = 16;
|
||||||
crcmask = 0xCCCC;
|
crcmask = 0xCCCC;
|
||||||
@@ -176,6 +183,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0B: //Unified Single Block Data USBD
|
case 0x0B: //Unified Single Block Data USBD
|
||||||
|
hota_enc = 1;
|
||||||
is_bptc = 1;
|
is_bptc = 1;
|
||||||
crclen = 16;
|
crclen = 16;
|
||||||
crcmask = 0x3333;
|
crcmask = 0x3333;
|
||||||
@@ -185,6 +193,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
//special types (not real data 'sync' bursts)
|
//special types (not real data 'sync' bursts)
|
||||||
case 0xEB: //Embedded Signalling
|
case 0xEB: //Embedded Signalling
|
||||||
|
hota_enc = 1;
|
||||||
crclen = 5;
|
crclen = 5;
|
||||||
is_emb = 1;
|
is_emb = 1;
|
||||||
pdu_len = 9;
|
pdu_len = 9;
|
||||||
@@ -246,28 +255,41 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
BPTCDeInterleaveDMRData(info, BPTCDeInteleavedData);
|
BPTCDeInterleaveDMRData(info, BPTCDeInteleavedData);
|
||||||
|
|
||||||
/* Extract the BPTC 196,96 DMR data */
|
/* Extract the BPTC 196,96 DMR data */
|
||||||
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, R);
|
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, bptc_res_bits, &is_ras);
|
||||||
|
|
||||||
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
|
|
||||||
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x04);
|
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
//debug print
|
//debug print
|
||||||
//fprintf (stderr, " RAS? %X - %d %d %d", BPTCReservedBits, R[0], R[1], R[2]);
|
if (bptc_res_bits[0] != 0 || bptc_res_bits[1] != 0 || bptc_res_bits[2] != 0)
|
||||||
|
fprintf (stderr, " BPTC R BITS: %d %d %d", bptc_res_bits[0], bptc_res_bits[1], bptc_res_bits[2]);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Convert the 96 bits BPTC data into 12 bytes */
|
//TODO: Checkdown no irrecoverable errors prior to OTA Decryption?
|
||||||
k = 0;
|
|
||||||
for(i = 0; i < 12; i++)
|
//Hytera OTA Encryption
|
||||||
|
if (state->hota_key_loaded && hota_enc)
|
||||||
|
hytera_ota_decrypt_bptc_96(state, BPTCDmrDataBit, databurst);
|
||||||
|
|
||||||
|
//Hytera Data Block Level Decryption
|
||||||
|
if (databurst == 0x7) //Rate 1_2 Data Only
|
||||||
{
|
{
|
||||||
BPTCDmrDataByte[i] = 0;
|
uint8_t bytes[12];
|
||||||
for(j = 0; j < 8; j++)
|
memset(bytes, 0, sizeof(bytes));
|
||||||
{
|
pack_bit_array_into_byte_array(BPTCDmrDataBit, bytes, 12);
|
||||||
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] << 1;
|
hytera_bp_data_decrypt(state, bytes, 12);
|
||||||
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] | (BPTCDmrDataBit[k] & 0x01);
|
hytera_ep_data_decrypt(opts, state, bytes, 12);
|
||||||
k++;
|
unpack_byte_array_into_bit_array(bytes, BPTCDmrDataBit, 12);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */
|
/* Convert the 96 bits BPTC data into 12 bytes */
|
||||||
|
pack_bit_array_into_byte_array(BPTCDmrDataBit, BPTCDmrDataByte, 12);
|
||||||
|
|
||||||
|
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
|
||||||
|
if (IrrecoverableErrors == 0 && BPTCDmrDataByte[1] == 0x68) is_ras = 0;
|
||||||
|
|
||||||
|
//make sure if this is a PI header, the FID is set to 0x10
|
||||||
|
if (IrrecoverableErrors == 0 && databurst == 0x00 && BPTCDmrDataByte[1] != 0x10) is_ras = 0;
|
||||||
|
|
||||||
|
/* Fill the CRC extracted */
|
||||||
CRCExtracted = 0;
|
CRCExtracted = 0;
|
||||||
for(i = 0; i < crclen; i++)
|
for(i = 0; i < crclen; i++)
|
||||||
{
|
{
|
||||||
@@ -279,7 +301,24 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
CRCExtracted = CRCExtracted ^ crcmask;
|
CRCExtracted = CRCExtracted ^ crcmask;
|
||||||
|
|
||||||
/* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */
|
/* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */
|
||||||
if (is_lc) CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
|
if (is_lc)
|
||||||
|
{
|
||||||
|
if (is_ras)
|
||||||
|
{
|
||||||
|
CRCComputed = ras_mac_calculator(state, BPTCDmrDataByte, 9, 1);
|
||||||
|
if (CRCComputed == CRCExtracted)
|
||||||
|
CRCCorrect = 1;
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
fprintf (stderr, " EXT: %06X; MAC: %06X;", CRCExtracted, CRCComputed);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
|
||||||
|
|
||||||
|
//Hytera OTA Encryption LC Context Creation for VLC Header
|
||||||
|
if (state->hota_key_loaded && CRCCorrect && databurst == 0x01)
|
||||||
|
hytera_create_lc_ctx(state, BPTCDmrDataBit);
|
||||||
|
}
|
||||||
|
|
||||||
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
|
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
|
||||||
else if (state->data_conf_data[slot] == 0 && databurst == 0x7)
|
else if (state->data_conf_data[slot] == 0 && databurst == 0x7)
|
||||||
@@ -315,20 +354,23 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
//run CCITT on other data forms
|
//run CCITT on other data forms
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
|
if (is_ras == 1)
|
||||||
|
{
|
||||||
|
CRCComputed = ras_mac_calculator(state, BPTCDmrDataByte, 10, 0);
|
||||||
|
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
fprintf (stderr, " EXT: %04X; MAC: %04X;", CRCExtracted, CRCComputed);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
|
||||||
|
|
||||||
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
|
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
|
||||||
else CRCCorrect = 0;
|
else CRCCorrect = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set the 'RAS Flag', if no irrecoverable errors but bad crc, only when enabled by user (to prevent a lot of bad data CSBKs)
|
|
||||||
if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1;
|
|
||||||
|
|
||||||
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
|
|
||||||
if (BPTCDmrDataByte[1] == 0x68) is_ras = 0;
|
|
||||||
|
|
||||||
//if this is a RAS system, set the CRC to okay if irrecoverable errors are okay
|
//if this is a RAS system, set the CRC to okay if irrecoverable errors are okay
|
||||||
//if we don't do this, then we can't view some data (CSBKs on RAS enabled systems)
|
//if we don't do this, then we can't view some data (CSBKs on RAS enabled systems)
|
||||||
if (is_ras == 1)
|
if (is_ras == 1 && state->ras_effective_key == 0)
|
||||||
{
|
{
|
||||||
crc_original_validity = CRCCorrect;
|
crc_original_validity = CRCCorrect;
|
||||||
CRCCorrect = 1;
|
CRCCorrect = 1;
|
||||||
@@ -344,17 +386,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Convert corrected x bytes into x*8 bits */
|
/* Convert corrected x bytes into x*8 bits */
|
||||||
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
|
unpack_byte_array_into_bit_array(BPTCDmrDataByte, BPTCDmrDataBit, pdu_len);
|
||||||
{
|
|
||||||
BPTCDmrDataBit[j + 0] = (BPTCDmrDataByte[i+pdu_start] >> 7) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 1] = (BPTCDmrDataByte[i+pdu_start] >> 6) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 2] = (BPTCDmrDataByte[i+pdu_start] >> 5) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 3] = (BPTCDmrDataByte[i+pdu_start] >> 4) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 4] = (BPTCDmrDataByte[i+pdu_start] >> 3) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 5] = (BPTCDmrDataByte[i+pdu_start] >> 2) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 6] = (BPTCDmrDataByte[i+pdu_start] >> 1) & 0x01;
|
|
||||||
BPTCDmrDataBit[j + 7] = (BPTCDmrDataByte[i+pdu_start] >> 0) & 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
//convert to DMR_PDU and DMR_PDU_bits
|
//convert to DMR_PDU and DMR_PDU_bits
|
||||||
for (i = 0; i < pdu_len; i++)
|
for (i = 0; i < pdu_len; i++)
|
||||||
@@ -398,8 +430,42 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
} /* End for(j = 0; j < 8; j++) */
|
} /* End for(j = 0; j < 8; j++) */
|
||||||
} /* End for(i = 0; i < 16; i++) */
|
} /* End for(i = 0; i < 16; i++) */
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
// if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 0)
|
||||||
|
// hytera_ota_search_emb_lc(state, BptcDataMatrix); //only run as a debug option
|
||||||
|
if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 1)
|
||||||
|
hytera_ota_decrypt_emb_lc(state, BptcDataMatrix);
|
||||||
|
|
||||||
/* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */
|
/* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */
|
||||||
IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit);
|
if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 0)
|
||||||
|
{
|
||||||
|
//just fill with all ones, would be garbage from FEC anyways
|
||||||
|
memset(LC_DataBit, 1, sizeof(LC_DataBit));
|
||||||
|
IrrecoverableErrors = 1;
|
||||||
|
|
||||||
|
//TODO: columns instead of rows to match application of keystream
|
||||||
|
#ifdef DEBUG_HOTA
|
||||||
|
fprintf(stderr, "\n BPTC 128: ");
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
fprintf (stderr, "%04X", (uint16_t)convert_bits_into_output(BptcDataMatrix[i], 16));
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (state->hota_enc_check == 1)
|
||||||
|
{
|
||||||
|
//just fill with all ones, would be garbage from FEC anyways
|
||||||
|
memset(LC_DataBit, 1, sizeof(LC_DataBit));
|
||||||
|
IrrecoverableErrors = 1;
|
||||||
|
|
||||||
|
//TODO: columns instead of rows to match application of keystream
|
||||||
|
#ifdef DEBUG_HOTA
|
||||||
|
fprintf(stderr, "\n BPTC 128: ");
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
fprintf (stderr, "%04X", (uint16_t)convert_bits_into_output(BptcDataMatrix[i], 16));
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit);
|
||||||
|
|
||||||
/* Reconstitute the 5 bit CRC */
|
/* Reconstitute the 5 bit CRC */
|
||||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5);
|
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5);
|
||||||
@@ -407,6 +473,16 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
/* Compute the 5 bit CRC */
|
/* Compute the 5 bit CRC */
|
||||||
CRCComputed = ComputeCrc5Bit(LC_DataBit);
|
CRCComputed = ComputeCrc5Bit(LC_DataBit);
|
||||||
|
|
||||||
|
//read ahead first two bytes, look for 1X10 or 2X10 pattern
|
||||||
|
uint16_t ras_test = (uint16_t)(ConvertBitIntoBytes(&LC_DataBit[0], 16) & 0x30FF);
|
||||||
|
if ((IrrecoverableErrors == 0) && (ras_test == 0x2010 || ras_test == 0x1010))
|
||||||
|
{
|
||||||
|
is_ras = 1;
|
||||||
|
if (state->ras_effective_key != 0)
|
||||||
|
CRCComputed = ras_mac_calculator(state, LC_DataBit, 9, 2);
|
||||||
|
}
|
||||||
|
else is_ras = 0;
|
||||||
|
|
||||||
if(CRCExtracted == CRCComputed) CRCCorrect = 1;
|
if(CRCExtracted == CRCComputed) CRCCorrect = 1;
|
||||||
else CRCCorrect = 0;
|
else CRCCorrect = 0;
|
||||||
|
|
||||||
@@ -440,6 +516,10 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
||||||
IrrecoverableErrors = viterbi_r34(tdibits, TrellisReturn);
|
IrrecoverableErrors = viterbi_r34(tdibits, TrellisReturn);
|
||||||
|
|
||||||
|
//Hytera Data Block Level Decryption
|
||||||
|
hytera_bp_data_decrypt(state, TrellisReturn, 18);
|
||||||
|
hytera_ep_data_decrypt(opts, state, TrellisReturn, 18);
|
||||||
|
|
||||||
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
|
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
|
||||||
//they may have been successfully corrected, the CRC will reveal as much
|
//they may have been successfully corrected, the CRC will reveal as much
|
||||||
|
|
||||||
@@ -518,6 +598,10 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
bit_ptr = 100; byte_ptr = 12-pdu_start;
|
bit_ptr = 100; byte_ptr = 12-pdu_start;
|
||||||
pack_bit_array_into_byte_array (info+bit_ptr, DMR_PDU+byte_ptr, 12);
|
pack_bit_array_into_byte_array (info+bit_ptr, DMR_PDU+byte_ptr, 12);
|
||||||
|
|
||||||
|
//Hytera Data Block Level Decryption
|
||||||
|
hytera_bp_data_decrypt(state, DMR_PDU, 24);
|
||||||
|
hytera_ep_data_decrypt(opts, state, DMR_PDU, 24);
|
||||||
|
|
||||||
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
||||||
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
||||||
|
|
||||||
@@ -593,19 +677,8 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
else fprintf (stderr, "Reserved %d ", usbd_st);
|
else fprintf (stderr, "Reserved %d ", usbd_st);
|
||||||
}
|
}
|
||||||
|
|
||||||
//set the original CRCCorrect back to its original value if the RAS flag was tripped
|
//set the original CRCCorrect back to its original value if the RAS flag was tripped (if no key value present)
|
||||||
if (is_ras == 1) CRCCorrect = crc_original_validity;
|
if (is_ras == 1 && state->ras_effective_key == 0) CRCCorrect = crc_original_validity;
|
||||||
|
|
||||||
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
|
|
||||||
// if (IrrecoverableErrors == 0 && CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) fprintf(stderr, "(CRC OK)");
|
|
||||||
|
|
||||||
// if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "%s", KYEL);
|
|
||||||
// fprintf(stderr, " (FEC OK)");
|
|
||||||
// fprintf (stderr, "%s", KNRM);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
|
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
|
||||||
{
|
{
|
||||||
@@ -614,16 +687,25 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
//print whether or not the 'RAS Field' bits are set to indicate RAS enabled (to be verified)
|
//print whether or not the 'RAS Field' bit is set to indicate RAS
|
||||||
if (is_ras == 1)
|
//detected for RAS enabled burst types and disposition if key available
|
||||||
|
if (IrrecoverableErrors == 0 && is_ras == 1 && (is_bptc || is_emb) && databurst != 0x05 && databurst != 0x07)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf (stderr, " -RAS ");
|
fprintf (stderr, " {RAS ");
|
||||||
//the value of this field seems to always, or usually, be 4, or just R[2] bit is set
|
if (state->ras_effective_key != 0 && CRCComputed != CRCExtracted)
|
||||||
if (opts->payload == 1) fprintf (stderr, "%X ", BPTCReservedBits);
|
fprintf (stderr, "Fail} ");
|
||||||
|
else if (state->ras_effective_key != 0 && CRCComputed == CRCExtracted)
|
||||||
|
fprintf (stderr, "Okay} ");
|
||||||
|
else if (state->ras_effective_key == 0)
|
||||||
|
fprintf (stderr, "Skip} ");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//might flicker the terminal on partially enabled systems, may need to find a better placement
|
||||||
|
if (IrrecoverableErrors == 0 && (is_bptc || is_emb) && databurst != 0x05 && databurst != 0x07 && databurst != 0x09)
|
||||||
|
state->dmr_is_ras = is_ras;
|
||||||
|
|
||||||
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && is_ras == 0 && databurst != 0x09 && databurst != 0x05)
|
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && is_ras == 0 && databurst != 0x09 && databurst != 0x05)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
@@ -639,9 +721,24 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
fprintf (stderr, " DMR PDU Payload ");
|
fprintf (stderr, " DMR PDU Payload ");
|
||||||
for (i = 0; i < pdu_len; i++)
|
for (i = 0; i < pdu_len; i++)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
fprintf (stderr, "%02X", DMR_PDU[i]);
|
||||||
|
#else
|
||||||
fprintf (stderr, "[%02X]", DMR_PDU[i]);
|
fprintf (stderr, "[%02X]", DMR_PDU[i]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//RAS 5-bit - always same differential
|
||||||
|
//calculation should be 5-bit portion of RAS Effective Key's Last byte & 0x1F
|
||||||
|
//5-bit + CRCComputed % 31 = CRCExtracted
|
||||||
|
#ifdef DEBUG_RAS
|
||||||
|
if (opts->payload == 1 && is_emb && is_ras)
|
||||||
|
{
|
||||||
|
int32_t diff = ((int32_t)CRCExtracted - (int32_t)CRCComputed + 31) % 31;
|
||||||
|
fprintf (stderr, " CRC CMP: %02X EXT: %02X DIFF: %02X", CRCComputed, CRCExtracted, diff);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//debug print
|
//debug print
|
||||||
// if (dbsn) fprintf (stderr, " SN %X", dbsn);
|
// if (dbsn) fprintf (stderr, " SN %X", dbsn);
|
||||||
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
|
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
|
||||||
|
|||||||
145
src/dmr_flco.c
145
src/dmr_flco.c
@@ -32,6 +32,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
int is_alias = 0;
|
int is_alias = 0;
|
||||||
int is_gps = 0;
|
int is_gps = 0;
|
||||||
UNUSED(capsite);
|
UNUSED(capsite);
|
||||||
|
int is_ras = 0;
|
||||||
|
|
||||||
//XPT 'Things'
|
//XPT 'Things'
|
||||||
int is_xpt = 0;
|
int is_xpt = 0;
|
||||||
@@ -75,10 +76,66 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
//Kirisun
|
//Kirisun
|
||||||
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40
|
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40
|
||||||
{
|
{
|
||||||
//disable late entry for DMRA, Flag 3 if encrypted, 0 if not
|
//disable late entry for DMRA, Flag 3 if encrypted, 0 if not
|
||||||
if (so & 0x40)
|
if (so & 0x40)
|
||||||
opts->dmr_le = 3;
|
opts->dmr_le = 3;
|
||||||
else opts->dmr_le = 0;
|
else opts->dmr_le = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Hytera OTA Check Enabled, Set SRC from VLC (TLC and ELC differ)
|
||||||
|
//NOTE: VLC will always be same for each radio if its a group call
|
||||||
|
//while this is not the true src, it should be unique
|
||||||
|
//TGT will also be random between calls in each VLC,
|
||||||
|
//so assign static value
|
||||||
|
if (state->hota_enc_check)
|
||||||
|
{
|
||||||
|
uint32_t t_target = 8686868;
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
if (slot == 0)
|
||||||
|
{
|
||||||
|
state->lastsrc = source;
|
||||||
|
state->lasttg = t_target;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state->lastsrcR = source;
|
||||||
|
state->lasttgR = t_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "\n%s", KYEL);
|
||||||
|
fprintf (stderr, " SLOT %d ", slot+1);
|
||||||
|
fprintf(stderr, "TGT=%u SRC=%u ", t_target, source);
|
||||||
|
fprintf (stderr, "Encrypted Pseudo Call Information");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type == 2)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n%s", KRED);
|
||||||
|
fprintf (stderr, " SLOT %d", slot+1);
|
||||||
|
fprintf (stderr, " TLC Encrypted;");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type == 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KRED);
|
||||||
|
fprintf (stderr, " SLOT %d", slot+1);
|
||||||
|
fprintf (stderr, " EMB LC Encrypted;");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//HOTA CTX was not recovered, so dump that and return;
|
||||||
|
else if (state->hota_key_loaded && state->hota_ctx_ok[slot] == 0 && type == 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KRED);
|
||||||
|
fprintf (stderr, " SLOT %d", slot+1);
|
||||||
|
fprintf (stderr, " EMB LC Missing CTX; Encrypted;");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//read ahead a little to get this for the xpt flag
|
//read ahead a little to get this for the xpt flag
|
||||||
@@ -117,6 +174,17 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
if (slot == 0) state->dmr_flco = flco;
|
if (slot == 0) state->dmr_flco = flco;
|
||||||
else state->dmr_flcoR = flco;
|
else state->dmr_flcoR = flco;
|
||||||
|
|
||||||
|
//debug output for potential RAS indicators on Moto Systems during EMB (0x2X and 0x1X indicators)
|
||||||
|
//TODO: Either leave handling of link control as is, or rework entire file to handle all the exceptions
|
||||||
|
//that have been added to it over the years.
|
||||||
|
if ( (flco & 0x30) && (fid == 0x10) && (type == 3) )
|
||||||
|
{
|
||||||
|
is_ras = 1;
|
||||||
|
UNUSED(is_ras);
|
||||||
|
// flco &= 0xCF; //mask off the RAS bits
|
||||||
|
//NOTE: Mask breaks below check on talker alias on RAS systems WIP: Fixing That
|
||||||
|
}
|
||||||
|
|
||||||
//FID 0x10 and FLCO 0x14, 0x15, 0x16 and 0x17 confirmed as Moto EMB Alias
|
//FID 0x10 and FLCO 0x14, 0x15, 0x16 and 0x17 confirmed as Moto EMB Alias
|
||||||
//Can probably assume FID 0x10 FLCO 0x18 is Moto EMB GPS -- to be tested
|
//Can probably assume FID 0x10 FLCO 0x18 is Moto EMB GPS -- to be tested
|
||||||
if ( fid == 0x10 && (flco == 0x14 || flco == 0x15 || flco == 0x16 || flco == 0x17 || flco == 0x18) )
|
if ( fid == 0x10 && (flco == 0x14 || flco == 0x15 || flco == 0x16 || flco == 0x17 || flco == 0x18) )
|
||||||
@@ -126,7 +194,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Embedded Talker Alias Header Only (format and len storage)
|
//Embedded Talker Alias Header Only (format and len storage)
|
||||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
if ((fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
||||||
{
|
{
|
||||||
is_alias = 1;
|
is_alias = 1;
|
||||||
dmr_talker_alias_lc_header(opts, state, slot, lc_bits);
|
dmr_talker_alias_lc_header(opts, state, slot, lc_bits);
|
||||||
@@ -140,7 +208,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Embedded GPS
|
//Embedded GPS
|
||||||
if ( (fid == 0 || fid == 0x68) && fid == 0 && type == 3 && flco == 0x08)
|
if ((fid == 0 || fid == 0x68) && type == 3 && flco == 0x08)
|
||||||
{
|
{
|
||||||
is_gps = 1;
|
is_gps = 1;
|
||||||
dmr_embedded_gps(opts, state, lc_bits);
|
dmr_embedded_gps(opts, state, lc_bits);
|
||||||
@@ -202,8 +270,29 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
goto END_FLCO;
|
goto END_FLCO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Tait Talker Alias
|
||||||
|
if (fid == 0x58 && flco == 0x08 && type == 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||||
|
fprintf (stderr, " Tait Talker Alias: ");
|
||||||
|
char tta_str[8]; memset(tta_str, 0, sizeof(tta_str));
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
tta_str[i] = (uint8_t)ConvertBitIntoBytes(&lc_bits[16+(i*8)], 8);
|
||||||
|
fprintf (stderr, "%s", tta_str);
|
||||||
|
uint32_t source = 0;
|
||||||
|
if (slot == 0)
|
||||||
|
source = state->lastsrc;
|
||||||
|
else source = state->lastsrcR;
|
||||||
|
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == source)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].alias, "%s; ", tta_str);
|
||||||
|
sprintf (state->generic_talker_alias[slot], "Talker Alias: %s; ", tta_str);
|
||||||
|
|
||||||
|
goto END_FLCO;
|
||||||
|
}
|
||||||
//Unknown Tait Things
|
//Unknown Tait Things
|
||||||
if (fid == 0x58)
|
else if (fid == 0x58)
|
||||||
{
|
{
|
||||||
//NOTE: fid 0x58 (tait) had a single flco 0x06 emb observed, but without the other blocks (4,5,7) for an alias
|
//NOTE: fid 0x58 (tait) had a single flco 0x06 emb observed, but without the other blocks (4,5,7) for an alias
|
||||||
//will need to observe this one, or just remove it from the list, going to isolate tait lc for now
|
//will need to observe this one, or just remove it from the list, going to isolate tait lc for now
|
||||||
@@ -453,6 +542,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
sprintf (state->generic_talker_alias[0], "%s", "");
|
sprintf (state->generic_talker_alias[0], "%s", "");
|
||||||
// sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
|
// sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
|
||||||
memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
memset(state->hota_lc_ctx[0], 0, sizeof(state->hota_lc_ctx[0]));
|
||||||
|
state->hota_ctx_ok[0] = 0;
|
||||||
|
state->hota_sbrc_idx1[0] = -1;
|
||||||
|
state->hota_sbrc_idx2[0] = -1;
|
||||||
}
|
}
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
{
|
{
|
||||||
@@ -473,6 +568,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
sprintf (state->generic_talker_alias[1], "%s", "");
|
sprintf (state->generic_talker_alias[1], "%s", "");
|
||||||
// sprintf (state->event_history_s[1].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
|
// sprintf (state->event_history_s[1].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
|
||||||
memset (state->dmr_pdu_sf[1], 0, sizeof(state->dmr_pdu_sf[1]));
|
memset (state->dmr_pdu_sf[1], 0, sizeof(state->dmr_pdu_sf[1]));
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
memset(state->hota_lc_ctx[1], 0, sizeof(state->hota_lc_ctx[1]));
|
||||||
|
state->hota_ctx_ok[1] = 0;
|
||||||
|
state->hota_sbrc_idx1[1] = -1;
|
||||||
|
state->hota_sbrc_idx2[1] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -500,15 +601,15 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
if (opts->payload == 1 && is_xpt == 1 && flco == 0x3) fprintf(stderr, "HASH=%d ", tg_hash);
|
if (opts->payload == 1 && is_xpt == 1 && flco == 0x3) fprintf(stderr, "HASH=%d ", tg_hash);
|
||||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||||
|
|
||||||
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
|
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator <--need to find this again and re-evaluate
|
||||||
//0x07 on a VLC seems to indicate a Cap+ Private Call Header
|
//0x04 on a VLC seems to indicate a Cap+ Group Call Header <--single bit flip from normal group
|
||||||
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ or Cap+ TXI Private Call in progress
|
//0x07 on a VLC seems to indicate a Cap+ Private Call Header <--single bit flip from normal private
|
||||||
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto (non-specific) Group Call in progress
|
//0x20 on the Embedded Voice Burst Sync seems to indicate a Moto w/ FID 0x10 Group Call in progress (RAS)
|
||||||
//its possible that both EMB FID 0x10 FLCO 0x20 and 0x23 are just Moto but non-specific (observed 0x20 on Tier 2)
|
//0x23 on the Embedded Voice Burst Sync seems to indicate a Moto w/ FID 0x10 Private Call in progress (RAS)
|
||||||
|
|
||||||
if (fid == 0x68) sprintf (state->call_string[slot], " Hytera ");
|
if (fid == 0x68) sprintf (state->call_string[slot], " Hytera ");
|
||||||
|
|
||||||
else if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
|
else if (flco == 0x4 || flco == 0x5 || flco == 0x7) //Cap+ Things (double check 0x05)
|
||||||
{
|
{
|
||||||
// sprintf (state->call_string[slot], " Cap+");
|
// sprintf (state->call_string[slot], " Cap+");
|
||||||
sprintf (state->call_string[slot], "%s","");
|
sprintf (state->call_string[slot], "%s","");
|
||||||
@@ -528,13 +629,13 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
state->gi[slot] = 1;
|
state->gi[slot] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (flco == 0x3) //UU_V_Ch_Usr
|
else if (flco == 0x3 || flco == 0x23) //UU_V_Ch_Usr
|
||||||
{
|
{
|
||||||
sprintf (state->call_string[slot], " Private ");
|
sprintf (state->call_string[slot], " Private ");
|
||||||
fprintf (stderr, "Private ");
|
fprintf (stderr, "Private ");
|
||||||
state->gi[slot] = 1;
|
state->gi[slot] = 1;
|
||||||
}
|
}
|
||||||
else //Grp_V_Ch_Usr -- still valid on hytera VLC
|
else //Grp_V_Ch_Usr
|
||||||
{
|
{
|
||||||
sprintf (state->call_string[slot], " Group ");
|
sprintf (state->call_string[slot], " Group ");
|
||||||
fprintf (stderr, "Group ");
|
fprintf (stderr, "Group ");
|
||||||
@@ -1191,7 +1292,19 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (slco == 0xF)
|
else if (slco == 0x5)
|
||||||
|
{
|
||||||
|
uint32_t unk = (uint32_t)ConvertBitIntoBytes(&slco_bits[4], 24);
|
||||||
|
fprintf (stderr, " SLCO Caltta: %06X;", unk);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (slco == 0xE)
|
||||||
|
{
|
||||||
|
uint32_t update_tgt = (uint32_t)ConvertBitIntoBytes(&slco_bits[4], 24);
|
||||||
|
fprintf (stderr, " SLCO Cap Max Activity Update; TGT: %d;", update_tgt);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (slco == 0xF) //This opcode has also been observed on Cap Max Payload Channels
|
||||||
{
|
{
|
||||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest LSN: %d - RS: %02X", capsite, restchannel, cap_reserved);
|
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest LSN: %d - RS: %02X", capsite, restchannel, cap_reserved);
|
||||||
|
|
||||||
|
|||||||
246
src/dmr_le.c
246
src/dmr_le.c
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
|
static unsigned long long int next_iv_32[2] = {0,0};
|
||||||
|
static unsigned long long int next_iv_64[2] = {0,0};
|
||||||
|
|
||||||
//gather ambe_fr mi fragments for processing
|
//gather ambe_fr mi fragments for processing
|
||||||
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24])
|
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24])
|
||||||
{
|
{
|
||||||
@@ -86,7 +89,96 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (g[0] && g[1] && g[2])
|
if (g[0] && g[1] && g[2])
|
||||||
{
|
{
|
||||||
if (slot == 0 && state->payload_algid != 0)
|
|
||||||
|
if (mi_crc_ok == 1 && state->hota_enc_check == 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
fprintf (stderr, " Slot %d DMRA EP Potential;", slot+1);
|
||||||
|
|
||||||
|
unsigned long long int temp_iv = mi_final;
|
||||||
|
|
||||||
|
//Reverse Potential IV for both 32-bit and 128-bit to show the IV
|
||||||
|
//that may have been carried by the PI header or last superframe
|
||||||
|
uint8_t iv_a[16]; memset(iv_a, 0, sizeof(iv_a));
|
||||||
|
uint8_t iv_d[16]; memset(iv_d, 0, sizeof(iv_d));
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
iv_a[i] = (mi_final >> (24-(i*8))) & 0xFF;
|
||||||
|
iv_d[i] = (mi_final >> (24-(i*8))) & 0xFF;
|
||||||
|
}
|
||||||
|
fprintf (stderr, "\n ");
|
||||||
|
reverse_lfsr_32a_to_len(iv_a, 32);
|
||||||
|
fprintf (stderr, " ");
|
||||||
|
reverse_lfsr_32d_to_len(iv_d, 32);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
if (next_iv_64[slot] != 0 && mi_final == next_iv_64[slot])
|
||||||
|
{
|
||||||
|
//probably safe to assume AES-256 if its DMRA specific
|
||||||
|
fprintf (stderr, " DMRA AES 128-bit IV detected;");
|
||||||
|
state->forced_alg_id = 0x25;
|
||||||
|
if (slot == 0 && state->payload_mi == 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
state->payload_mi = mi_final;
|
||||||
|
state->dmr_so = 0x40;
|
||||||
|
LFSR128d(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (slot == 1 && state->payload_miR == 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
state->payload_miR = mi_final;
|
||||||
|
state->dmr_soR = 0x40;
|
||||||
|
LFSR128d(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (next_iv_32[slot] != 0 && mi_final == next_iv_32[slot])
|
||||||
|
{
|
||||||
|
//only DMRA RC4 uses this tap configuration
|
||||||
|
fprintf (stderr, " DMRA RC4 32-bit IV detected;");
|
||||||
|
state->forced_alg_id = 0x21;
|
||||||
|
if (slot == 0 && state->payload_mi == 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
state->payload_mi = mi_final;
|
||||||
|
state->dmr_so = 0x40;
|
||||||
|
LFSR(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (slot == 1 && state->payload_miR == 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
state->payload_miR = mi_final;
|
||||||
|
state->dmr_soR = 0x40;
|
||||||
|
LFSR(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//AES taps to next embedded value
|
||||||
|
for(int cnt = 0; cnt < 32; cnt++)
|
||||||
|
{
|
||||||
|
unsigned long long int bit = ( (temp_iv >> 31) ^ (temp_iv >> 21) ^ (temp_iv >> 1) ^ (temp_iv >> 0) ) & 0x1;
|
||||||
|
temp_iv = (temp_iv << 1) | bit;
|
||||||
|
}
|
||||||
|
next_iv_64[slot] = temp_iv & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
//RC4 taps to next embedded value
|
||||||
|
temp_iv = mi_final;
|
||||||
|
for(int cnt = 0; cnt < 32; cnt++)
|
||||||
|
{
|
||||||
|
unsigned long long int bit = ( (temp_iv >> 31) ^ (temp_iv >> 3) ^ (temp_iv >> 1) ) & 0x1;
|
||||||
|
temp_iv = (temp_iv << 1) | bit;
|
||||||
|
}
|
||||||
|
next_iv_32[slot] = temp_iv & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == 0 && state->payload_algid != 0 && state->payload_algid != 0x26)
|
||||||
{
|
{
|
||||||
if (state->payload_mi != mi_final)
|
if (state->payload_mi != mi_final)
|
||||||
{
|
{
|
||||||
@@ -116,7 +208,7 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (slot == 1 && state->payload_algidR != 0)
|
if (slot == 1 && state->payload_algidR != 0 && state->payload_algidR != 0x26)
|
||||||
{
|
{
|
||||||
if (state->payload_miR != mi_final)
|
if (state->payload_miR != mi_final)
|
||||||
{
|
{
|
||||||
@@ -219,20 +311,37 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, "%s\n", KNRM);
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->payload_algid == 0x35 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
if ((state->payload_algid & 0xF0) == 0x30) //any kirisun 0x3X alg
|
||||||
{
|
{
|
||||||
|
uint8_t alg = state->payload_algid;
|
||||||
state->DMRvcL = 0;
|
state->DMRvcL = 0;
|
||||||
state->payload_mi = kirisun_lfsr(state->payload_mi);
|
state->payload_mi = kirisun_lfsr(state->payload_mi);
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Slot 1");
|
fprintf (stderr, " Slot 1");
|
||||||
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algid, state->payload_keyid);
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", alg, state->payload_keyid);
|
||||||
fprintf (stderr, " MI(32): %08llX;", state->payload_mi);
|
fprintf (stderr, " MI(32): %08llX;", state->payload_mi);
|
||||||
fprintf (stderr, " Kirisun");
|
fprintf (stderr, " Kirisun ");
|
||||||
if (state->payload_algid == 0x36)
|
if (alg == 0x31)
|
||||||
fprintf (stderr, " Advanced;");
|
fprintf (stderr, "Reinforced ");
|
||||||
else if (state->payload_algid == 0x37)
|
else if (alg == 0x32)
|
||||||
fprintf (stderr, " Universal;");
|
fprintf (stderr, "Low ");
|
||||||
else fprintf (stderr, " Encryption;");
|
else if (alg == 0x33)
|
||||||
|
fprintf (stderr, "Middle ");
|
||||||
|
else if (alg == 0x34)
|
||||||
|
fprintf (stderr, "High ");
|
||||||
|
else if (alg == 0x35)
|
||||||
|
fprintf (stderr, "Enhanced ");
|
||||||
|
else if (alg == 0x36)
|
||||||
|
fprintf (stderr, "Advanced ");
|
||||||
|
else if (alg == 0x37)
|
||||||
|
fprintf (stderr, "Universal ");
|
||||||
|
else if (alg == 0x38)
|
||||||
|
fprintf (stderr, "Strengthened ");
|
||||||
|
else if (alg == 0x39)
|
||||||
|
fprintf (stderr, "Top ");
|
||||||
|
else if (alg == 0x3A)
|
||||||
|
fprintf (stderr, "Ultra ");
|
||||||
|
fprintf (stderr, "Encryption;");
|
||||||
fprintf (stderr, "%s\n", KNRM);
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,20 +375,37 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, "%s\n", KNRM);
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->payload_algidR == 0x35 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
if ((state->payload_algidR & 0xF0) == 0x30) //any 0x3X alg
|
||||||
{
|
{
|
||||||
|
uint8_t alg = state->payload_algidR;
|
||||||
state->DMRvcR = 0;
|
state->DMRvcR = 0;
|
||||||
state->payload_miR = kirisun_lfsr(state->payload_miR);
|
state->payload_miR = kirisun_lfsr(state->payload_miR);
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algidR, state->payload_keyidR);
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", alg, state->payload_keyidR);
|
||||||
fprintf (stderr, " MI(32): %08llX;", state->payload_miR);
|
fprintf (stderr, " MI(32): %08llX;", state->payload_miR);
|
||||||
fprintf (stderr, " Kirisun");
|
fprintf (stderr, " Kirisun ");
|
||||||
if (state->payload_algidR == 0x36)
|
if (alg == 0x31)
|
||||||
fprintf (stderr, " Advanced;");
|
fprintf (stderr, "Reinforced ");
|
||||||
else if (state->payload_algidR == 0x37)
|
else if (alg == 0x32)
|
||||||
fprintf (stderr, " Universal;");
|
fprintf (stderr, "Low ");
|
||||||
else fprintf (stderr, " Encryption;");
|
else if (alg == 0x33)
|
||||||
|
fprintf (stderr, "Middle ");
|
||||||
|
else if (alg == 0x34)
|
||||||
|
fprintf (stderr, "High ");
|
||||||
|
else if (alg == 0x35)
|
||||||
|
fprintf (stderr, "Enhanced ");
|
||||||
|
else if (alg == 0x36)
|
||||||
|
fprintf (stderr, "Advanced ");
|
||||||
|
else if (alg == 0x37)
|
||||||
|
fprintf (stderr, "Universal ");
|
||||||
|
else if (alg == 0x38)
|
||||||
|
fprintf (stderr, "Strengthened ");
|
||||||
|
else if (alg == 0x39)
|
||||||
|
fprintf (stderr, "Top ");
|
||||||
|
else if (alg == 0x3A)
|
||||||
|
fprintf (stderr, "Ultra ");
|
||||||
|
fprintf (stderr, "Encryption;");
|
||||||
fprintf (stderr, "%s\n", KNRM);
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,6 +457,13 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
// 1 - The embedded signalling carries RC information associated to the other logical channel
|
// 1 - The embedded signalling carries RC information associated to the other logical channel
|
||||||
|
|
||||||
for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8];
|
for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8];
|
||||||
|
|
||||||
|
//decrypt for Hytera OTA Encryption w/ loaded key
|
||||||
|
if (state->hota_key_loaded && state->hota_sbrc_idx1[state->currentslot] == -1)
|
||||||
|
hytera_ota_search_sb_rc(state, sbrc_interleaved, power);
|
||||||
|
if (state->hota_key_loaded)
|
||||||
|
hytera_ota_decrypt_sb_rc(state, sbrc_interleaved);
|
||||||
|
|
||||||
//power == 0 should be single burst
|
//power == 0 should be single burst
|
||||||
if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0);
|
if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0);
|
||||||
//power == 1 should be reverse channel -- still need to check the interleave inside of BPTC
|
//power == 1 should be reverse channel -- still need to check the interleave inside of BPTC
|
||||||
@@ -338,6 +471,36 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
//bad emb burst, never set a valid power indicator value (probably 9)
|
//bad emb burst, never set a valid power indicator value (probably 9)
|
||||||
if (power > 1) goto SBRC_END;
|
if (power > 1) goto SBRC_END;
|
||||||
|
|
||||||
|
//Hytera OTA
|
||||||
|
if (irr_err && state->hota_key_loaded && state->hota_sbrc_idx2[state->currentslot] == -1)
|
||||||
|
{
|
||||||
|
state->hota_sbrc_idx1[state->currentslot] = -1;
|
||||||
|
state->hota_sbrc_idx2[state->currentslot] = -1;
|
||||||
|
fprintf (stderr, "%s \n", KRED);
|
||||||
|
fprintf (stderr, " SLOT %d ", slot+1);
|
||||||
|
fprintf (stderr, "SB_RC Missing IDX; Encrypted;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
goto SBRC_END;
|
||||||
|
}
|
||||||
|
else if (irr_err && state->hota_key_loaded && state->hota_sbrc_idx2[state->currentslot] != -1)
|
||||||
|
{
|
||||||
|
state->hota_sbrc_idx1[state->currentslot] = -1;
|
||||||
|
state->hota_sbrc_idx2[state->currentslot] = -1;
|
||||||
|
fprintf (stderr, "%s \n", KRED);
|
||||||
|
fprintf (stderr, " SLOT %d ", slot+1);
|
||||||
|
fprintf (stderr, "SB_RC Incorrect IDX or FEC Errors; Encrypted;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
goto SBRC_END;
|
||||||
|
}
|
||||||
|
else if (state->hota_enc_check)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s \n", KRED);
|
||||||
|
fprintf (stderr, " SLOT %d ", slot+1);
|
||||||
|
fprintf (stderr, "SB_RC Encrypted;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
goto SBRC_END;
|
||||||
|
}
|
||||||
|
|
||||||
//arrange the return for proper order for the crc3 check
|
//arrange the return for proper order for the crc3 check
|
||||||
for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3];
|
for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3];
|
||||||
|
|
||||||
@@ -407,7 +570,7 @@ 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
|
//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?)
|
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
|
||||||
|
|
||||||
//Kirisun Placeholder
|
//Kirisun
|
||||||
if (opts->dmr_le == 3)
|
if (opts->dmr_le == 3)
|
||||||
{
|
{
|
||||||
if (irr_err != 0)
|
if (irr_err != 0)
|
||||||
@@ -422,23 +585,38 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
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);
|
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");
|
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?
|
else if (irr_err == 0 && sbrc_hex != 0) //older firmware had sbrc_hex 0x5F1, and 0x5E1 instead
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot %d", state->currentslot+1);
|
fprintf (stderr, " Slot %d", state->currentslot+1);
|
||||||
fprintf (stderr, " DMR LE SB Kirisun Encryption Identifier;");
|
fprintf (stderr, " DMR LE SB Kirisun");
|
||||||
|
|
||||||
|
//Newer Samples and/or updated firmware seem to do this with actual key values
|
||||||
|
uint8_t alg = sbrc_hex >> 7;
|
||||||
|
|
||||||
|
if (alg != 0xB)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " ALG: %02X;", alg+0x30);
|
||||||
|
uint8_t kid = (sbrc_hex >> 3) & 0xF;
|
||||||
|
fprintf (stderr, " KID: %02X;", kid);
|
||||||
|
uint8_t unk = sbrc_hex & 0x7;
|
||||||
|
fprintf (stderr, " LOW3: %X;", unk);
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
if (state->payload_algid == 0 && state->dmr_so & 0x40)
|
||||||
|
state->payload_algid = alg+0x30;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (state->payload_algidR == 0 && state->dmr_soR & 0x40)
|
||||||
|
state->payload_algidR = alg+0x30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,6 +706,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
if (alg == 2) fprintf (stderr, " DES;");
|
if (alg == 2) fprintf (stderr, " DES;");
|
||||||
if (alg == 4) fprintf (stderr, " AES128;");
|
if (alg == 4) fprintf (stderr, " AES128;");
|
||||||
if (alg == 5) fprintf (stderr, " AES256;");
|
if (alg == 5) fprintf (stderr, " AES256;");
|
||||||
|
if (alg == 6) fprintf (stderr, " Caltta BP");
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
if (state->payload_keyid != key)
|
if (state->payload_keyid != key)
|
||||||
@@ -550,6 +729,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: %02X; KEY ID: %02X;", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: %02X; KEY ID: %02X;", alg + 0x20, key);
|
||||||
|
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 == 6) fprintf (stderr, " Caltta BP");
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
if (state->payload_keyidR != key)
|
if (state->payload_keyidR != key)
|
||||||
|
|||||||
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 + 0] = syncdata[i];
|
||||||
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
||||||
|
|
||||||
@@ -270,6 +260,13 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->vtx256_ekey != 0)
|
||||||
|
{
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr2);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PRINT_AMBE72
|
#ifdef PRINT_AMBE72
|
||||||
ambe2_codeword_print_i(opts, ambe_fr);
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
@@ -588,6 +585,13 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->vtx256_ekey != 0)
|
||||||
|
{
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr2);
|
||||||
|
vtx256_ambe2_interleave_inversion(ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PRINT_AMBE72
|
#ifdef PRINT_AMBE72
|
||||||
ambe2_codeword_print_i(opts, ambe_fr);
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
ambe2_codeword_print_i(opts, ambe_fr2);
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
|
|||||||
@@ -267,8 +267,13 @@ void dmr_udp_comp_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t
|
|||||||
slot = 1;
|
slot = 1;
|
||||||
|
|
||||||
char comp_string[500]; memset (comp_string, 0, sizeof(comp_string));
|
char comp_string[500]; memset (comp_string, 0, sizeof(comp_string));
|
||||||
sprintf (comp_string, "IPC: %d; OP: %d; SRC: %d:%d (%s):(%s); DST: %d:%d (%s):(%s); ", ipid, opcode, said, spid, addrstring[0], portstring[0], daid, dpid, addrstring[1], portstring[1]);
|
|
||||||
watchdog_event_datacall (opts, state, said, daid, comp_string, slot);
|
//use data header source and target instead of idx values
|
||||||
|
uint32_t source = state->dmr_lrrp_source[slot];
|
||||||
|
uint32_t target = state->dmr_lrrp_target[slot];
|
||||||
|
sprintf (comp_string, "IPC Call; SRC: %d; TGT: %d; %s", source, target, portstring);
|
||||||
|
// sprintf (comp_string, "IPC: %d; OP: %d; SRC: %d:%d (%s):(%s); DST: %d:%d (%s):(%s); ", ipid, opcode, said, spid, addrstring[0], portstring[0], daid, dpid, addrstring[1], portstring[1]);
|
||||||
|
watchdog_event_datacall (opts, state, source, target, comp_string, slot);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,29 +491,24 @@ void decode_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t *
|
|||||||
else if (port1 == 5007 && port2 == 5007)
|
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; ");
|
fprintf (stderr, "VTX STD TMS; ");
|
||||||
|
|
||||||
//+28, get 9 bytes for unknown "header" information
|
int tmslen = input[28];
|
||||||
//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)
|
//+29, get 8 bytes for unknown "header" information
|
||||||
|
//unknown elements 0002000000000000, could include type (utf-16, utf-8, is07?)
|
||||||
|
//the sample has a len of 14 utf-16 chars, corresponding to the found 0x0E value
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
// fprintf (stderr, "Len: %03d; ", len);
|
fprintf (stderr, "Len: %03d; ", tmslen);
|
||||||
fprintf (stderr, "??: ");
|
fprintf (stderr, "??: ");
|
||||||
for (int i = 0; i < 9; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
fprintf (stderr, "%02X", input[i+28]);
|
fprintf (stderr, "%02X", input[i+29]);
|
||||||
fprintf (stderr, "; Text: ");
|
fprintf (stderr, "; Text: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf (state->dmr_lrrp_gps[slot], "VTX TMS SRC: %d; DST: %d; ", src24, dst24);
|
sprintf (state->dmr_lrrp_gps[slot], "VTX TMS SRC: %d; DST: %d; ", src24, dst24);
|
||||||
utf16_to_text(state, 1, len, input+49);
|
utf16_to_text(state, 1, tmslen*2, input+37);
|
||||||
}
|
}
|
||||||
else if (port1 == 5017 && port2 == 5017)
|
else if (port1 == 5017 && port2 == 5017)
|
||||||
{
|
{
|
||||||
|
|||||||
97
src/dmr_pi.c
97
src/dmr_pi.c
@@ -27,51 +27,68 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
|||||||
|
|
||||||
if (MFID == 0x0A && CRCCorrect == 1) //Kirisun
|
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
|
//NOTE: Some Kirisun Radios seem to use byte 2 as the SVC_OPT, others seem to use it like a KID value
|
||||||
|
// 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 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
|
//NOTE: Original samples had this as 0x40 no matter which "key" was selected, new samples from different radio show a KID value
|
||||||
|
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 on older FW
|
||||||
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);
|
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
|
//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)
|
uint8_t hash = alg * target % 256; //more complex hash later (honestly, probably not)
|
||||||
|
|
||||||
|
//Only set real KID if the byte value isn't 0x40
|
||||||
|
if (kid == 0x40)
|
||||||
|
kid = hash;
|
||||||
|
|
||||||
//MI only appears to be 32-bit
|
//MI only appears to be 32-bit
|
||||||
uint32_t mi = ((uint32_t)PI_BYTE[3] << 24) | ((uint32_t)PI_BYTE[4] << 16) |
|
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);
|
((uint32_t)PI_BYTE[5] << 8) | ((uint32_t)PI_BYTE[6] << 0);
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
state->dmr_so = so;
|
state->dmr_so = 0x40;
|
||||||
state->payload_algid = alg;
|
state->payload_algid = alg;
|
||||||
state->payload_keyid = hash;
|
state->payload_keyid = kid;
|
||||||
state->payload_mi = mi;
|
state->payload_mi = mi;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state->dmr_soR = so;
|
state->dmr_soR = 0x40;
|
||||||
state->payload_algidR = alg;
|
state->payload_algidR = alg;
|
||||||
state->payload_keyidR = hash;
|
state->payload_keyidR = kid;
|
||||||
state->payload_miR = mi;
|
state->payload_miR = mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KYEL);
|
fprintf (stderr, "%s ", KYEL);
|
||||||
fprintf (stderr, "\n Slot %d", state->currentslot+1);
|
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, " DMR PI H- ALG ID: %02X; TGT: %d; KEY ID: %02X; MI(32): %08X;", alg, target, kid, mi);
|
||||||
|
|
||||||
fprintf (stderr, " Kirisun ");
|
fprintf (stderr, " Kirisun ");
|
||||||
if (alg == 0x36)
|
if (alg == 0x31)
|
||||||
fprintf (stderr, "Advanced;");
|
fprintf (stderr, "Reinforced ");
|
||||||
|
else if (alg == 0x32)
|
||||||
|
fprintf (stderr, "Low ");
|
||||||
|
else if (alg == 0x33)
|
||||||
|
fprintf (stderr, "Middle ");
|
||||||
|
else if (alg == 0x34)
|
||||||
|
fprintf (stderr, "High ");
|
||||||
|
else if (alg == 0x35)
|
||||||
|
fprintf (stderr, "Enhanced ");
|
||||||
|
else if (alg == 0x36)
|
||||||
|
fprintf (stderr, "Advanced ");
|
||||||
else if (alg == 0x37)
|
else if (alg == 0x37)
|
||||||
fprintf (stderr, "Universal;");
|
fprintf (stderr, "Universal ");
|
||||||
else fprintf (stderr, "Encryption;");
|
else if (alg == 0x38)
|
||||||
|
fprintf (stderr, "Strengthened ");
|
||||||
|
else if (alg == 0x39)
|
||||||
|
fprintf (stderr, "Top ");
|
||||||
|
else if (alg == 0x3A)
|
||||||
|
fprintf (stderr, "Ultra ");
|
||||||
|
fprintf (stderr, "Encryption;");
|
||||||
fprintf (stderr, "%s", KNRM);
|
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
|
//flag late entry SB for Kirisun
|
||||||
//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;
|
opts->dmr_le = 3;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -146,7 +163,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
|||||||
state->payload_algid = PI_BYTE[0];
|
state->payload_algid = PI_BYTE[0];
|
||||||
state->payload_keyid = PI_BYTE[2];
|
state->payload_keyid = PI_BYTE[2];
|
||||||
state->payload_mi = ((unsigned long long int)PI_BYTE[3] << 24ULL) | ((unsigned long long int)PI_BYTE[4] << 16ULL) | ((unsigned long long int)PI_BYTE[5] << 8ULL) | ((unsigned long long int)PI_BYTE[6] << 0ULL);
|
state->payload_mi = ((unsigned long long int)PI_BYTE[3] << 24ULL) | ((unsigned long long int)PI_BYTE[4] << 16ULL) | ((unsigned long long int)PI_BYTE[5] << 8ULL) | ((unsigned long long int)PI_BYTE[6] << 0ULL);
|
||||||
if (state->payload_algid < 0x26)
|
if (state->payload_algid < 0x28)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s ", KYEL);
|
fprintf (stderr, "%s ", KYEL);
|
||||||
fprintf (stderr, "\n Slot 1");
|
fprintf (stderr, "\n Slot 1");
|
||||||
@@ -182,6 +199,13 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
|||||||
state->payload_algid = 0x25;
|
state->payload_algid = 0x25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algid & 0x07) == 0x06)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Caltta BP;");
|
||||||
|
state->payload_algid = 0x26;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
|
||||||
//expand the 32-bit MI to a 64-bit DES IV
|
//expand the 32-bit MI to a 64-bit DES IV
|
||||||
@@ -199,7 +223,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->payload_algid >= 0x26)
|
if (state->payload_algid >= 0x28)
|
||||||
{
|
{
|
||||||
state->payload_algid = 0;
|
state->payload_algid = 0;
|
||||||
state->payload_keyid = 0;
|
state->payload_keyid = 0;
|
||||||
@@ -249,6 +273,12 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
|||||||
state->payload_algidR = 0x25;
|
state->payload_algidR = 0x25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algidR & 0x07) == 0x06)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Caltta BP;");
|
||||||
|
state->payload_algidR = 0x26;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
|
||||||
@@ -267,7 +297,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->payload_algidR >= 0x26)
|
if (state->payload_algidR >= 0x28)
|
||||||
{
|
{
|
||||||
state->payload_algidR = 0;
|
state->payload_algidR = 0;
|
||||||
state->payload_keyidR = 0;
|
state->payload_keyidR = 0;
|
||||||
@@ -374,6 +404,33 @@ void LFSR64(dsd_state * state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if supplied IV is only 32-bit in value, then expand it to a 128-bit IV using these LFSR taps (packed array)
|
||||||
|
void lfsr_32_to_128(uint8_t * iv)
|
||||||
|
{
|
||||||
|
uint64_t lfsr = 0, bit = 0;
|
||||||
|
|
||||||
|
lfsr = ((uint64_t)iv[0] << 24ULL) + ((uint64_t)iv[1] << 16ULL) + ((uint64_t)iv[2] << 8ULL) + ((uint64_t)iv[3] << 0ULL);
|
||||||
|
|
||||||
|
uint8_t cnt = 0, x = 32;
|
||||||
|
|
||||||
|
for(cnt = 0;cnt < 96; cnt++)
|
||||||
|
{
|
||||||
|
//32,22,2,1 (per Xilinx XAPP 052) Table 3: Taps for Maximum-Length LFSR Counters
|
||||||
|
bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
|
||||||
|
lfsr = (lfsr << 1) | bit;
|
||||||
|
|
||||||
|
//continue packing iv
|
||||||
|
iv[x/8] = (iv[x/8] << 1) + bit;
|
||||||
|
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "\n IV(128): ");
|
||||||
|
for (x = 0; x < 16; x++)
|
||||||
|
fprintf (stderr, "%02X", iv[x]);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//Expand a 32-bit MI into a 128-bit IV for AES
|
//Expand a 32-bit MI into a 128-bit IV for AES
|
||||||
void LFSR128d(dsd_state * state)
|
void LFSR128d(dsd_state * state)
|
||||||
|
|||||||
@@ -438,3 +438,43 @@ uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData)
|
|||||||
/* Return the CRC */
|
/* Return the CRC */
|
||||||
return CRC;
|
return CRC;
|
||||||
} /* End ComputeCrc32Bit() */
|
} /* End ComputeCrc32Bit() */
|
||||||
|
|
||||||
|
uint32_t ComputeCrc32BitV(uint8_t * DMRData, uint32_t NbData)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t CRC = 0x00000000; /* Initialization value = 0x00000000 */
|
||||||
|
/* Polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
|
||||||
|
* Normal = 0x04C11DB7
|
||||||
|
* Reversed = 0xEDB88320
|
||||||
|
* Reciprocal = 0xDB710641
|
||||||
|
* Reversed reciprocal = 0x82608EDB */
|
||||||
|
uint32_t Polynome = 0x04C11DB7;
|
||||||
|
for(i = 0; i < NbData; i++)
|
||||||
|
{
|
||||||
|
if(((CRC >> 31) & 1) ^ (DMRData[i] & 1))
|
||||||
|
{
|
||||||
|
CRC = (CRC << 1) ^ Polynome;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CRC <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Alternate Return Configuration for Vertex
|
||||||
|
//Encrypted PDUs that have already been reordered once before
|
||||||
|
//CRC32 CMP: 1622377A EXT: 377A1622
|
||||||
|
uint32_t a, b, c, d;
|
||||||
|
a = b = c = d = 0;
|
||||||
|
|
||||||
|
a = ((CRC >> 0) & 0xFF) << 16;
|
||||||
|
b = ((CRC >> 8) & 0xFF) << 24;
|
||||||
|
c = ((CRC >> 16) & 0xFF) << 0;
|
||||||
|
d = ((CRC >> 24) & 0xFF) << 8;
|
||||||
|
|
||||||
|
CRC = a + b + c + d;
|
||||||
|
|
||||||
|
/* Return the CRC */
|
||||||
|
return CRC;
|
||||||
|
} /* End ComputeCrc32BitV() */
|
||||||
|
|
||||||
|
|||||||
101
src/dsd_audio2.c
101
src/dsd_audio2.c
@@ -92,6 +92,10 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
encL = 0;
|
encL = 0;
|
||||||
}
|
}
|
||||||
|
else if (state->vtx_key_loaded == 1)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state->payload_algid == 0x02 || state->payload_algid == 0x21 || state->payload_algid == 0x22)
|
else if (state->payload_algid == 0x02 || state->payload_algid == 0x21 || state->payload_algid == 0x22)
|
||||||
{
|
{
|
||||||
@@ -100,7 +104,7 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encL = 0;
|
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
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
if (state->aes_key_loaded[0] == 1)
|
if (state->aes_key_loaded[0] == 1)
|
||||||
@@ -108,6 +112,21 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encL = 0;
|
encL = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A)
|
||||||
|
{
|
||||||
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
|
if (state->aes_key_loaded[0] == 1)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state->payload_algid == 0x26)
|
||||||
|
{
|
||||||
|
if (state->straight_ks == 0x26)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encR)
|
if (encR)
|
||||||
@@ -118,6 +137,10 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
encR = 0;
|
encR = 0;
|
||||||
}
|
}
|
||||||
|
else if (state->vtx_key_loaded == 1)
|
||||||
|
{
|
||||||
|
encR = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state->payload_algidR == 0x02 ||state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
|
else if (state->payload_algidR == 0x02 ||state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
|
||||||
{
|
{
|
||||||
@@ -126,7 +149,7 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encR = 0;
|
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
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
if (state->aes_key_loaded[1] == 1)
|
if (state->aes_key_loaded[1] == 1)
|
||||||
@@ -134,6 +157,21 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encR = 0;
|
encR = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algidR >= 0x31 && state->payload_algidR <= 0x3A)
|
||||||
|
{
|
||||||
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
|
if (state->aes_key_loaded[1] == 1)
|
||||||
|
{
|
||||||
|
encR = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state->payload_algidR == 0x26)
|
||||||
|
{
|
||||||
|
if (state->straight_ks == 0x26)
|
||||||
|
{
|
||||||
|
encR = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug disable enc check for AES testing
|
//debug disable enc check for AES testing
|
||||||
@@ -716,13 +754,28 @@ void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state)
|
|||||||
encL = 0;
|
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)
|
if (state->aes_key_loaded[0] == 1)
|
||||||
{
|
{
|
||||||
encL = 0;
|
encL = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A)
|
||||||
|
{
|
||||||
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
|
if (state->aes_key_loaded[0] == 1)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state->payload_algidR == 0x26)
|
||||||
|
{
|
||||||
|
if (state->straight_ks == 0x26)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
//WIP: Mute if on B list (or not W list)
|
||||||
@@ -1123,6 +1176,10 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
encL = 0;
|
encL = 0;
|
||||||
}
|
}
|
||||||
|
else if (state->vtx_key_loaded == 1)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state->payload_algid == 0x02 || state->payload_algid == 0x21 || state->payload_algid == 0x22)
|
else if (state->payload_algid == 0x02 || state->payload_algid == 0x21 || state->payload_algid == 0x22)
|
||||||
{
|
{
|
||||||
@@ -1131,7 +1188,7 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encL = 0;
|
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
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
if (state->aes_key_loaded[0] == 1)
|
if (state->aes_key_loaded[0] == 1)
|
||||||
@@ -1139,6 +1196,21 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encL = 0;
|
encL = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A)
|
||||||
|
{
|
||||||
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
|
if (state->aes_key_loaded[0] == 1)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state->payload_algid == 0x26)
|
||||||
|
{
|
||||||
|
if (state->straight_ks == 0x26)
|
||||||
|
{
|
||||||
|
encL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encR)
|
if (encR)
|
||||||
@@ -1149,6 +1221,10 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
encR = 0;
|
encR = 0;
|
||||||
}
|
}
|
||||||
|
else if (state->vtx_key_loaded == 1)
|
||||||
|
{
|
||||||
|
encR = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state->payload_algidR == 0x02 ||state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
|
else if (state->payload_algidR == 0x02 ||state->payload_algidR == 0x21 || state->payload_algidR == 0x22)
|
||||||
{
|
{
|
||||||
@@ -1157,7 +1233,7 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encR = 0;
|
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
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
if (state->aes_key_loaded[1] == 1)
|
if (state->aes_key_loaded[1] == 1)
|
||||||
@@ -1165,6 +1241,21 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|||||||
encR = 0;
|
encR = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algidR >= 0x31 && state->payload_algidR <= 0x3A)
|
||||||
|
{
|
||||||
|
//going to need a better check for this later on, or seperated keys or something
|
||||||
|
if (state->aes_key_loaded[1] == 1)
|
||||||
|
{
|
||||||
|
encR = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state->payload_algidR == 0x26)
|
||||||
|
{
|
||||||
|
if (state->straight_ks == 0x26)
|
||||||
|
{
|
||||||
|
encR = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug for AES
|
//debug for AES
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
@@ -121,22 +122,46 @@ use_symbol (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
UNUSED(symbol);
|
UNUSED(symbol);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int sbuf2[128];
|
|
||||||
int lmin, lmax, lsum;
|
int lmin, lmax, lsum;
|
||||||
|
int lmn[2] = {INT_MAX, INT_MAX};
|
||||||
|
int lmx[2] = {INT_MIN, INT_MIN};
|
||||||
|
|
||||||
|
// single-pass tracking of the 2 smallest and 2 largest values in the symbol window
|
||||||
for (i = 0; i < opts->ssize; i++)
|
for (i = 0; i < opts->ssize; i++)
|
||||||
{
|
{
|
||||||
sbuf2[i] = state->sbuf[i];
|
int x = state->sbuf[i];
|
||||||
|
if (x < lmn[1])
|
||||||
|
{
|
||||||
|
if (x < lmn[0])
|
||||||
|
{
|
||||||
|
lmn[1] = lmn[0];
|
||||||
|
lmn[0] = x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lmn[1] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x > lmx[1])
|
||||||
|
{
|
||||||
|
if (x > lmx[0])
|
||||||
|
{
|
||||||
|
lmx[1] = lmx[0];
|
||||||
|
lmx[0] = x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lmx[1] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort (sbuf2, opts->ssize, sizeof (int), comp);
|
|
||||||
|
|
||||||
// continuous update of min/max in rf_mod=1 (QPSK) mode
|
// continuous update of min/max in rf_mod=1 (QPSK) mode
|
||||||
// in c4fm min/max must only be updated during sync
|
// in c4fm min/max must only be updated during sync
|
||||||
if (state->rf_mod == 1)
|
if (state->rf_mod == 1)
|
||||||
{
|
{
|
||||||
lmin = (sbuf2[0] + sbuf2[1]) / 2;
|
lmin = (lmn[0] + lmn[1]) / 2;
|
||||||
lmax = (sbuf2[(opts->ssize - 1)] + sbuf2[(opts->ssize - 2)]) / 2;
|
lmax = (lmx[1] + lmx[0]) / 2;
|
||||||
state->minbuf[state->midx] = lmin;
|
state->minbuf[state->midx] = lmin;
|
||||||
state->maxbuf[state->midx] = lmax;
|
state->maxbuf[state->midx] = lmax;
|
||||||
if (state->midx == (opts->msize - 1))
|
if (state->midx == (opts->msize - 1))
|
||||||
@@ -178,7 +203,7 @@ use_symbol (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
|
|
||||||
if (opts->datascope == 1)
|
if (opts->datascope == 1)
|
||||||
{
|
{
|
||||||
print_datascope(opts, state, sbuf2);
|
print_datascope(opts, state, state->sbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
170
src/dsd_file.c
170
src/dsd_file.c
@@ -877,6 +877,76 @@ void unpack_ambe (uint8_t * input, char * ambe)
|
|||||||
ambe[48] = input[6] >> 7;
|
ambe[48] = input[6] >> 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t reverse_lfsr_32a_to_len(uint8_t * iv, int16_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t lfsr = 0, bit1 = 0, bit2 = 0;
|
||||||
|
|
||||||
|
lfsr = ((uint64_t)iv[0] << 24ULL) + ((uint64_t)iv[1] << 16ULL) + ((uint64_t)iv[2] << 8ULL) + ((uint64_t)iv[3] << 0ULL);
|
||||||
|
|
||||||
|
memset (iv, 0, 8*sizeof(uint8_t));
|
||||||
|
|
||||||
|
for(int16_t cnt = 0; cnt < len; cnt++)
|
||||||
|
{
|
||||||
|
//32,22,2,1 (per Xilinx XAPP 052) Table 3: Taps for Maximum-Length LFSR Counters
|
||||||
|
|
||||||
|
//taps at the +1 position on all but MSB, then check the LSB and configure bit as required
|
||||||
|
bit1 = ( (lfsr >> 22) ^ (lfsr >> 2) ^ (lfsr >> 1) ) & 0x1;
|
||||||
|
bit2 = lfsr & 1;
|
||||||
|
if (bit1 == bit2)
|
||||||
|
bit2 = 0;
|
||||||
|
else bit2 = 1;
|
||||||
|
|
||||||
|
//just run this in reverse of normal LFSR
|
||||||
|
lfsr = (lfsr >> 1) | (bit2 << 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < 4; i++)
|
||||||
|
iv[i] = (lfsr >> (24-(i*8))) & 0xFF;
|
||||||
|
|
||||||
|
fprintf (stderr, "REV LFSR AES(%02d): ", len);
|
||||||
|
for (int16_t i = 0; i < 4; i++)
|
||||||
|
fprintf (stderr, "%02X", iv[i]);
|
||||||
|
|
||||||
|
return bit2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t reverse_lfsr_32d_to_len(uint8_t * iv, int16_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t lfsr = 0, bit1 = 0, bit2 = 0;
|
||||||
|
|
||||||
|
lfsr = ((uint64_t)iv[0] << 24ULL) + ((uint64_t)iv[1] << 16ULL) + ((uint64_t)iv[2] << 8ULL) + ((uint64_t)iv[3] << 0ULL);
|
||||||
|
|
||||||
|
memset (iv, 0, 8*sizeof(uint8_t));
|
||||||
|
|
||||||
|
for(int16_t cnt = 0; cnt < len; cnt++)
|
||||||
|
{
|
||||||
|
//magical taps that somebody must have dreamt up
|
||||||
|
|
||||||
|
//taps at the +1 position on all but MSB, then check the LSB and configure bit as required
|
||||||
|
bit1 = ((lfsr >> 4) ^ (lfsr >> 2)) & 0x1;
|
||||||
|
bit2 = lfsr & 1;
|
||||||
|
if (bit1 == bit2)
|
||||||
|
bit2 = 0;
|
||||||
|
else bit2 = 1;
|
||||||
|
|
||||||
|
//just run this in reverse of normal LFSR
|
||||||
|
lfsr = (lfsr >> 1) | (bit2 << 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < 4; i++)
|
||||||
|
iv[i] = (lfsr >> (24-(i*8))) & 0xFF;
|
||||||
|
|
||||||
|
fprintf (stderr, "REV LFSR RC4(%02d): ", len);
|
||||||
|
for (int16_t i = 0; i < 4; i++)
|
||||||
|
fprintf (stderr, "%02X", iv[i]);
|
||||||
|
|
||||||
|
return bit2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//recover previous IV for SDRTrunk .mbe files when P25p1
|
//recover previous IV for SDRTrunk .mbe files when P25p1
|
||||||
uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len)
|
uint64_t reverse_lfsr_64_to_len(dsd_opts * opts, uint8_t * iv, int16_t len)
|
||||||
{
|
{
|
||||||
@@ -1027,7 +1097,7 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
|
|||||||
//force slot to 0
|
//force slot to 0
|
||||||
state->currentslot = 0;
|
state->currentslot = 0;
|
||||||
|
|
||||||
uint8_t c3_hex = (uint64_t)ConvertBitIntoBytes(c3, 4);
|
uint8_t c3_hex = (uint8_t)ConvertBitIntoBytes(c3, 4);
|
||||||
|
|
||||||
//debug
|
//debug
|
||||||
// fprintf (stderr, "\n AMBE#: %02d / %d / %d; F: %X;", ambe2_counter, ambe2_counter/3, ambe2_counter%3, c3_hex);
|
// fprintf (stderr, "\n AMBE#: %02d / %d / %d; F: %X;", ambe2_counter, ambe2_counter/3, ambe2_counter%3, c3_hex);
|
||||||
@@ -1035,17 +1105,6 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
|
|||||||
//use div and mod 3 to set current storage fragment
|
//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;
|
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));
|
char ambe_d[49]; memset(ambe_d, 0, sizeof(ambe_d));
|
||||||
@@ -1561,6 +1620,60 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if ((alg_id == 0x24 || alg_id == 0x25) && state->payload_mi != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t ks_bytes[375];
|
||||||
|
memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
|
||||||
|
uint8_t aes_key[32];
|
||||||
|
memset(aes_key, 0, sizeof(aes_key));
|
||||||
|
|
||||||
|
uint8_t empty[32];
|
||||||
|
memset(empty, 0, sizeof(empty));
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check to see if a key is actually loaded
|
||||||
|
if (memcmp (aes_key, empty, sizeof(aes_key)) != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (alg_id == 0x24) //128, or 256
|
||||||
|
aes_ofb_keystream_output(state->aes_iv, aes_key, ks_bytes, 0, 16); //16*16=256
|
||||||
|
else aes_ofb_keystream_output(state->aes_iv, aes_key, ks_bytes, 2, 16); //16*16=256
|
||||||
|
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes+16, ks, 256-16); //unpack starting after discards
|
||||||
|
|
||||||
|
ks_available = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Forced Application of DMRA DES Mode (untested on .mbe real samples)
|
||||||
|
if (alg_id == 0x22 && state->R != 0 && state->payload_mi != 0)
|
||||||
|
{
|
||||||
|
//expand IV from 32 to 64 (late entry iv should fix this)
|
||||||
|
// if (alg_id == 0x22)
|
||||||
|
// LFSR64(state);
|
||||||
|
|
||||||
|
uint8_t ks_bytes[375];
|
||||||
|
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+8, ks, 256-8);
|
||||||
|
|
||||||
|
ks_available = 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//TODO: This
|
//TODO: This
|
||||||
else if (state->forced_alg_id == 1) //Basic Privacy
|
else if (state->forced_alg_id == 1) //Basic Privacy
|
||||||
@@ -1700,7 +1813,11 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
//debug set value
|
//debug set value
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
fprintf (stderr, "\n IV: %016llX;", iv_hex); //not really needed if loaded into array
|
{
|
||||||
|
if (iv_hex > 0xFFFFFFFF)
|
||||||
|
fprintf (stderr, "\n IV: %016llX;", iv_hex);
|
||||||
|
else fprintf (stderr, "\n IV: %08llX;", iv_hex);
|
||||||
|
}
|
||||||
|
|
||||||
//debug print current str_buffer
|
//debug print current str_buffer
|
||||||
// fprintf (stderr, "\n Encryption MI/IV: %s", str_buffer);
|
// fprintf (stderr, "\n Encryption MI/IV: %s", str_buffer);
|
||||||
@@ -1752,10 +1869,14 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//P25 DES (v1 tested and working on P1, v2 should be okay now)
|
//P25 and DMR DES (v1 tested and working on P1, v2 should be okay now), DMR Untested but should be okay
|
||||||
else if (alg_id == 0x81 && state->R != 0)
|
else if ((alg_id == 0x22 || alg_id == 0x81) && state->R != 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//expand IV from 32 to 64
|
||||||
|
if (alg_id == 0x22)
|
||||||
|
LFSR64(state);
|
||||||
|
|
||||||
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
|
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
|
||||||
|
|
||||||
if (protocol == 1) //Phase 1 IMBE start on 19 for DES-OFB (8 discard + 9 LCW + 2 reserved)
|
if (protocol == 1) //Phase 1 IMBE start on 19 for DES-OFB (8 discard + 9 LCW + 2 reserved)
|
||||||
@@ -1792,8 +1913,8 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//P25 AES (v1 and v2 tested working on P1)
|
//P25 and DMR AES (v1 and v2 tested working on P1), working on DMR
|
||||||
else if ( (alg_id == 0x84 || alg_id == 0x89) && state->aes_key_loaded[0] == 1 )
|
else if ( (alg_id == 0x24 || alg_id == 0x25 || alg_id == 0x84 || alg_id == 0x89) && state->aes_key_loaded[0] == 1 )
|
||||||
{
|
{
|
||||||
|
|
||||||
uint8_t aes_key[32];
|
uint8_t aes_key[32];
|
||||||
@@ -1821,9 +1942,11 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
|||||||
aes_last_iv[i] = aes_iv[i];
|
aes_last_iv[i] = aes_iv[i];
|
||||||
|
|
||||||
//Resolve the longer IV from the shorter one
|
//Resolve the longer IV from the shorter one
|
||||||
lfsr_64_to_128(aes_iv);
|
if (alg_id == 0x24 || alg_id == 0x25)
|
||||||
|
lfsr_32_to_128(aes_iv);
|
||||||
|
else lfsr_64_to_128(aes_iv);
|
||||||
|
|
||||||
if (alg_id == 0x89) //128, or 256
|
if (alg_id == 0x89 || alg_id == 0x24) //128, or 256
|
||||||
aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 0, 16); //16*16=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
|
else aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 2, 16); //16*16=256
|
||||||
|
|
||||||
@@ -1987,6 +2110,15 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
|
|||||||
//reset if over for DMR 18 AMBE+2 frames
|
//reset if over for DMR 18 AMBE+2 frames
|
||||||
if (dmra_le && ambe2_counter == 18)
|
if (dmra_le && ambe2_counter == 18)
|
||||||
{
|
{
|
||||||
|
//run LFSR evaluate stored codewords for matching IV or replace if not match or not set
|
||||||
|
if (state->forced_alg_id == 0x21 && state->payload_mi != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
LFSR(state);
|
||||||
|
}
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
dmr_late_entry_mi (opts, state);
|
||||||
|
|
||||||
ambe2_counter = 0;
|
ambe2_counter = 0;
|
||||||
ks_idx = 0;
|
ks_idx = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
#include <limits.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -164,7 +165,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
char synctest8[9]; //M17
|
char synctest8[9]; //M17
|
||||||
char modulation[8];
|
char modulation[8];
|
||||||
char *synctest_p;
|
char *synctest_p;
|
||||||
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
char synctest_buf[10240 + 48]; //history for sync matching; look-back window up to 48 bytes
|
||||||
int lmin, lmax, lidx;
|
int lmin, lmax, lidx;
|
||||||
|
|
||||||
//assign t_max value based on decoding type expected (all non-auto decodes first)
|
//assign t_max value based on decoding type expected (all non-auto decodes first)
|
||||||
@@ -197,11 +198,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else t_max = 24; //24 for everything else
|
else t_max = 24; //24 for everything else
|
||||||
|
|
||||||
int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
|
int lbuf[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
|
||||||
int lsum;
|
int lsum;
|
||||||
//init the lbuf
|
//init the lbuf
|
||||||
memset (lbuf, 0, sizeof(lbuf));
|
memset (lbuf, 0, sizeof(lbuf));
|
||||||
memset (lbuf2, 0, sizeof(lbuf2));
|
|
||||||
|
|
||||||
// detect frame sync
|
// detect frame sync
|
||||||
t = 0;
|
t = 0;
|
||||||
@@ -214,7 +214,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
synctest20[20] = 0;
|
synctest20[20] = 0;
|
||||||
modulation[7] = 0; //not initialized or terminated (unsure if this would be an issue or not)
|
modulation[7] = 0; //not initialized or terminated (unsure if this would be an issue or not)
|
||||||
synctest_pos = 0;
|
synctest_pos = 0;
|
||||||
synctest_p = synctest_buf + 10;
|
synctest_p = synctest_buf + 48;
|
||||||
sync = 0;
|
sync = 0;
|
||||||
lmin = 0;
|
lmin = 0;
|
||||||
lmax = 0;
|
lmax = 0;
|
||||||
@@ -374,23 +374,37 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
*synctest_p = dibit;
|
*synctest_p = dibit;
|
||||||
if (t >= t_max) //works excelent now with short sync patterns, and no issues with large ones!
|
if (t >= t_max) //works excelent now with short sync patterns, and no issues with large ones!
|
||||||
{
|
{
|
||||||
|
int lmn[5] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX};
|
||||||
|
int lmx[5] = {INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN};
|
||||||
|
int j, x;
|
||||||
for (i = 0; i < t_max; i++) //24
|
for (i = 0; i < t_max; i++) //24
|
||||||
{
|
{
|
||||||
lbuf2[i] = lbuf[i];
|
x = lbuf[i];
|
||||||
|
if (x < lmn[4])
|
||||||
|
{
|
||||||
|
for (j = 4; j > 0 && x < lmn[j - 1]; j--)
|
||||||
|
lmn[j] = lmn[j - 1];
|
||||||
|
lmn[j] = x;
|
||||||
|
}
|
||||||
|
if (x > lmx[4])
|
||||||
|
{
|
||||||
|
for (j = 4; j > 0 && x > lmx[j - 1]; j--)
|
||||||
|
lmx[j] = lmx[j - 1];
|
||||||
|
lmx[j] = x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
qsort (lbuf2, t_max, sizeof (int), comp);
|
|
||||||
|
|
||||||
//on shorter sync patterns, we need to look at the edges since we don't have many to pull from
|
//on shorter sync patterns, we need to look at the edges since we don't have many to pull from
|
||||||
if (t_max < 13)
|
if (t_max < 13)
|
||||||
{
|
{
|
||||||
lmin = (lbuf2[0] + lbuf2[1] + lbuf2[2]) / 3;
|
lmin = (lmn[0] + lmn[1] + lmn[2]) / 3;
|
||||||
lmax = (lbuf2[t_max - 3] + lbuf2[t_max - 2] + lbuf2[t_max - 1]) / 3;
|
lmax = (lmx[2] + lmx[1] + lmx[0]) / 3;
|
||||||
}
|
}
|
||||||
//on longer sync patterns, we can get more towards the middle and eliminate outlier values
|
//on longer sync patterns, we can get more towards the middle and eliminate outlier values
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lmin = (lbuf2[2] + lbuf2[3] + lbuf2[4]) / 3;
|
lmin = (lmn[2] + lmn[3] + lmn[4]) / 3;
|
||||||
lmax = (lbuf2[t_max - 5] + lbuf2[t_max - 4] + lbuf2[t_max - 3]) / 3;
|
lmax = (lmx[4] + lmx[3] + lmx[2]) / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->rf_mod == 1)
|
if (state->rf_mod == 1)
|
||||||
@@ -1374,7 +1388,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
// buffer reset
|
// buffer reset
|
||||||
synctest_pos = 0;
|
synctest_pos = 0;
|
||||||
synctest_p = synctest_buf;
|
synctest_p = synctest_buf + 48;
|
||||||
noCarrier (opts, state);
|
noCarrier (opts, state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -528,7 +528,7 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
if (slot == 1) src = state->lasttgR;
|
if (slot == 1) src = state->lasttgR;
|
||||||
|
|
||||||
//save to event history string
|
//save to event history string
|
||||||
if (state->event_history_s[slot].Event_History_Items[0].source_id == src)
|
// if (state->event_history_s[slot].Event_History_Items[0].source_id == src)
|
||||||
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
|
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
//save to LRRP report for mapping/logging
|
||||||
|
|||||||
247
src/dsd_main.c
247
src/dsd_main.c
@@ -83,15 +83,6 @@
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int comp (const void *a, const void *b)
|
|
||||||
{
|
|
||||||
if (*((const int *) a) == *((const int *) b))
|
|
||||||
return 0;
|
|
||||||
else if (*((const int *) a) < *((const int *) b))
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//struct for checking existence of directory to write to
|
//struct for checking existence of directory to write to
|
||||||
struct stat st = {0};
|
struct stat st = {0};
|
||||||
@@ -437,6 +428,11 @@
|
|||||||
state->K2 = 0;
|
state->K2 = 0;
|
||||||
state->K3 = 0;
|
state->K3 = 0;
|
||||||
state->K4 = 0;
|
state->K4 = 0;
|
||||||
|
//vertex standard keys
|
||||||
|
// memset(state->vtx256_key, 0, sizeof(state->vtx256_key));
|
||||||
|
state->vtx40_key = 0;
|
||||||
|
state->vtx256_ekey = 0;
|
||||||
|
state->vtx_key_loaded = 0;
|
||||||
memset (state->A1, 0, sizeof(state->A1));
|
memset (state->A1, 0, sizeof(state->A1));
|
||||||
memset (state->A2, 0, sizeof(state->A2));
|
memset (state->A2, 0, sizeof(state->A2));
|
||||||
memset (state->A3, 0, sizeof(state->A3));
|
memset (state->A3, 0, sizeof(state->A3));
|
||||||
@@ -590,6 +586,14 @@
|
|||||||
//we do reset the counter, but not the static_ks_bits
|
//we do reset the counter, but not the static_ks_bits
|
||||||
memset (state->static_ks_counter, 0, sizeof(state->static_ks_counter));
|
memset (state->static_ks_counter, 0, sizeof(state->static_ks_counter));
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
memset(state->hota_lc_ctx, 0, sizeof(state->hota_lc_ctx));
|
||||||
|
memset(state->hota_ctx_ok, 0, sizeof(state->hota_ctx_ok));
|
||||||
|
state->hota_sbrc_idx1[0] = -1;
|
||||||
|
state->hota_sbrc_idx2[0] = -1;
|
||||||
|
state->hota_sbrc_idx1[1] = -1;
|
||||||
|
state->hota_sbrc_idx2[1] = -1;
|
||||||
|
|
||||||
} //nocarrier
|
} //nocarrier
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -699,6 +703,9 @@
|
|||||||
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->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_started = 0;
|
||||||
opts->rtl_rms = 0; //root means square power level on rtl input signal
|
opts->rtl_rms = 0; //root means square power level on rtl input signal
|
||||||
|
opts->rtltcp_enabled = 0; //1 when the rtl input is an rtl_tcp server instead of a local dongle
|
||||||
|
sprintf (opts->rtltcp_hostname, "%s", "localhost");
|
||||||
|
opts->rtltcp_portno = 1234; //rtl_tcp default port
|
||||||
//end RTL user options
|
//end RTL user options
|
||||||
opts->pulse_raw_rate_in = 48000;
|
opts->pulse_raw_rate_in = 48000;
|
||||||
opts->pulse_raw_rate_out = 48000;//
|
opts->pulse_raw_rate_out = 48000;//
|
||||||
@@ -1068,6 +1075,7 @@
|
|||||||
state->any_bp = 0;
|
state->any_bp = 0;
|
||||||
state->straight_ks = 0;
|
state->straight_ks = 0;
|
||||||
state->straight_mod = 0;
|
state->straight_mod = 0;
|
||||||
|
state->straight_discard = 0;
|
||||||
|
|
||||||
//ks array storage and counters
|
//ks array storage and counters
|
||||||
memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
|
memset (state->ks_octetL, 0, sizeof(state->ks_octetL));
|
||||||
@@ -1094,6 +1102,12 @@
|
|||||||
//xl specific, we need to know if the ESS is from HDU, or from LDU2
|
//xl specific, we need to know if the ESS is from HDU, or from LDU2
|
||||||
state->xl_is_hdu = 0;
|
state->xl_is_hdu = 0;
|
||||||
|
|
||||||
|
//vertex standard keys
|
||||||
|
memset(state->vtx256_key, 0, sizeof(state->vtx256_key));
|
||||||
|
state->vtx40_key = 0;
|
||||||
|
state->vtx256_ekey = 0;
|
||||||
|
state->vtx_key_loaded = 0;
|
||||||
|
|
||||||
//NXDN, when a new IV has arrived
|
//NXDN, when a new IV has arrived
|
||||||
state->nxdn_new_iv = 0;
|
state->nxdn_new_iv = 0;
|
||||||
|
|
||||||
@@ -1235,6 +1249,26 @@
|
|||||||
state->dmr_end_alert[0] = 0;
|
state->dmr_end_alert[0] = 0;
|
||||||
state->dmr_end_alert[1] = 0;
|
state->dmr_end_alert[1] = 0;
|
||||||
|
|
||||||
|
//RAS
|
||||||
|
memset (state->ras_permutation_order, 0, sizeof(state->ras_permutation_order));
|
||||||
|
state->ras_effective_key = 0;
|
||||||
|
state->dmr_is_ras = 0;
|
||||||
|
|
||||||
|
//Hytera OTA Encryption
|
||||||
|
state->hota_enc_check = 0;
|
||||||
|
state->hota_key_loaded = 0;
|
||||||
|
state->dmr_is_hota = 0;
|
||||||
|
state->hota_bit_shift = 0;
|
||||||
|
memset(state->hota_byte_shifts, 0, sizeof(state->hota_byte_shifts));
|
||||||
|
memset(state->hota_rc4_key, 0, sizeof(state->hota_rc4_key));
|
||||||
|
memset(state->hota_rc4_ks, 0, sizeof(state->hota_rc4_ks));
|
||||||
|
memset(state->hota_lc_ctx, 0, sizeof(state->hota_lc_ctx));
|
||||||
|
memset(state->hota_ctx_ok, 0, sizeof(state->hota_ctx_ok));
|
||||||
|
state->hota_sbrc_idx1[0] = -1;
|
||||||
|
state->hota_sbrc_idx2[0] = -1;
|
||||||
|
state->hota_sbrc_idx1[1] = -1;
|
||||||
|
state->hota_sbrc_idx2[1] = -1;
|
||||||
|
|
||||||
sprintf (state->dmr_branding, "%s", "");
|
sprintf (state->dmr_branding, "%s", "");
|
||||||
sprintf (state->dmr_branding_sub, "%s", "");
|
sprintf (state->dmr_branding_sub, "%s", "");
|
||||||
sprintf (state->dmr_site_parms, "%s", "");
|
sprintf (state->dmr_site_parms, "%s", "");
|
||||||
@@ -1398,6 +1432,7 @@
|
|||||||
printf (" pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O) \n");
|
printf (" pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O) \n");
|
||||||
printf (" rtl for rtl dongle (Default Values -- see below)\n");
|
printf (" rtl for rtl dongle (Default Values -- see below)\n");
|
||||||
printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n");
|
printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n");
|
||||||
|
printf (" rtltcp:host:port:freq:gain:ppm:bw:sq:vol for rtl dongle on an rtl_tcp server (see below)\n");
|
||||||
printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\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 (" tcp:192.168.7.5:7355 for custom address and port \n");
|
||||||
printf (" filename.bin for OP25/FME capture bin files\n");
|
printf (" filename.bin for OP25/FME capture bin files\n");
|
||||||
@@ -1452,7 +1487,7 @@
|
|||||||
printf (" If using /dev/dsp input and output at 48k1, launch two instances of DSD-FME w -V 1 and -V 2 if needed\n");
|
printf (" If using /dev/dsp input and output at 48k1, launch two instances of DSD-FME w -V 1 and -V 2 if needed\n");
|
||||||
#endif
|
#endif
|
||||||
printf (" -z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)\n");
|
printf (" -z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)\n");
|
||||||
printf (" -y Enable Experimental Pulse Audio Float Audio Output\n");
|
// printf (" -y Enable Experimental Pulse Audio Float Audio Output\n");
|
||||||
printf (" -v <hex> Set Filtering Bitmap Options (Advanced Option)\n");
|
printf (" -v <hex> Set Filtering Bitmap Options (Advanced Option)\n");
|
||||||
printf (" 1 1 1 1 (0xF): PBF/LPF/HPF/HPFD on\n");
|
printf (" 1 1 1 1 (0xF): PBF/LPF/HPF/HPFD on\n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
@@ -1469,6 +1504,11 @@
|
|||||||
printf (" vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)\n");
|
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 -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 (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2\n");
|
||||||
|
printf (" Usage: rtltcp:host:port:freq:gain:ppm:bw:sq:vol\n");
|
||||||
|
printf (" host <name> rtl_tcp Server Hostname or IP Address (default = localhost)\n");
|
||||||
|
printf (" port <num> rtl_tcp Server Port (default = 1234)\n");
|
||||||
|
printf (" freq, gain, ppm, bw, sq, vol as above\n");
|
||||||
|
printf (" Example: dsd-fme -fs -i rtltcp:192.168.1.10:1234:450M:26:-2:8 -C connect_plus_chan.csv -T\n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf ("Decoder options:\n");
|
printf ("Decoder options:\n");
|
||||||
printf (" -fa Auto Detection\n");
|
printf (" -fa Auto Detection\n");
|
||||||
@@ -1492,7 +1532,7 @@
|
|||||||
printf (" -fE Decode only EDACS EA/ProVoice with ESK 0xA0*\n");
|
printf (" -fE Decode only EDACS EA/ProVoice with ESK 0xA0*\n");
|
||||||
printf (" -fm Decode only dPMR*\n");
|
printf (" -fm Decode only dPMR*\n");
|
||||||
printf (" -l Disable DMR, dPMR, NXDN, M17 input filtering\n");
|
printf (" -l Disable DMR, dPMR, NXDN, M17 input filtering\n");
|
||||||
printf (" -u <num> Unvoiced speech quality (default=3)\n");
|
// printf (" -u <num> Unvoiced speech quality (default=3)\n");
|
||||||
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
||||||
printf (" -xr Expect inverted DMR signal\n");
|
printf (" -xr Expect inverted DMR signal\n");
|
||||||
printf (" -xd Expect inverted ICOM dPMR signal\n");
|
printf (" -xd Expect inverted ICOM dPMR signal\n");
|
||||||
@@ -1534,11 +1574,20 @@
|
|||||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||||
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf (" -H <hex> Manually Enter AES-128, AES-256, or Kirisun-256 Hex Key (see example below)\n");
|
printf (" -H <hex> Manually Enter AES-128, AES-256, or Kirisun 128 or 256 Hex Key (see example below)\n");
|
||||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||||
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
|
printf (" -H <hex> Manually Enter Caltta 10/32/64 Char Basic Privacy Hex Key (see example below)\n");
|
||||||
|
printf (" -H C:40:1234567890 \n");
|
||||||
|
printf (" -H C:128:736B9A9C5645288B243AD5CB8701EF8A' \n");
|
||||||
|
printf (" -H C:256:20029736A5D91042C923EB0697484433005EFC58A1905195E28E9C7836AA2DB8' \n");
|
||||||
|
printf ("\n");
|
||||||
|
printf (" -H <hex> Manually Enter Hytera OTA Encryption 32 Char Hex Key (see example below)\n");
|
||||||
|
printf (" -H O:0:0 no keystream application, but check for Hytera OTA Encryption and DMRA EP Late Entry IV.\n");
|
||||||
|
printf (" -H O:128:17bfe59b29a06136fb7d3811fd1a4904 for 128-bit RC4 OTA Key Setup\n");
|
||||||
|
printf ("\n");
|
||||||
printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
|
printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
|
||||||
printf (" \n");
|
printf (" \n");
|
||||||
printf (" -1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n");
|
printf (" -1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value) \n");
|
||||||
@@ -1571,6 +1620,23 @@
|
|||||||
printf (" \n");
|
printf (" \n");
|
||||||
printf (" -A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value) \n");
|
printf (" -A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value) \n");
|
||||||
printf (" \n");
|
printf (" \n");
|
||||||
|
printf (" -$ <string> Enter RAS Password 6-24 Char Key Value (DMR) (a-z A-Z, 0-9, $ # _ -) \n");
|
||||||
|
printf (" -$ Password123\n");
|
||||||
|
printf (" \n");
|
||||||
|
printf (" Special Use Cases involving # and $, use parenthesis and put \\ in front of all $ signs\n");
|
||||||
|
printf (" -$ \"######\"\n");
|
||||||
|
printf (" -$ \"\\$\\$\\$\\$\\$\\$\"\n");
|
||||||
|
printf (" \n");
|
||||||
|
printf (" -y <hex> Enter RAS 56-bit Effective Key Value (DMR) (14 Char Hex Value) \n");
|
||||||
|
printf (" -y 6DF241BC4AE2EC\n");
|
||||||
|
printf (" \n");
|
||||||
|
printf (" -, <string> Manually Enter and Enforce Auctus A6 (GoComm) 8 Char Key Value (DMR) (String Value) \n");
|
||||||
|
printf (" -, Secure04\n");
|
||||||
|
printf (" \n");
|
||||||
|
printf (" -u <string> Manually Enter Vertex Standard 10 or 64 Char Hex Key \n");
|
||||||
|
printf (" -u 10:1234567891 or 64:AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD\n");
|
||||||
|
printf (" -u 0:0 no KS application, but apply the inversion to the interleave (clear errors on 256)\n");
|
||||||
|
printf (" \n");
|
||||||
printf (" -S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)\n");
|
printf (" -S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)\n");
|
||||||
printf (" For Example, enter 16-bit Keystream 0909 as:\n");
|
printf (" For Example, enter 16-bit Keystream 0909 as:\n");
|
||||||
printf (" -S 16:0909\n");
|
printf (" -S 16:0909\n");
|
||||||
@@ -1580,6 +1646,8 @@
|
|||||||
printf (" -S 49:ED0AED4AED4AED4A\n");
|
printf (" -S 49:ED0AED4AED4AED4A\n");
|
||||||
printf (" For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:\n");
|
printf (" For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:\n");
|
||||||
printf (" -S 49:11AA22BB33CC44\n");
|
printf (" -S 49:11AA22BB33CC44\n");
|
||||||
|
printf (" For Example, Caltta 40-bit Keystream w/ optional 7-bit discard as:\n");
|
||||||
|
printf (" -S 40:1234567890:7\n");
|
||||||
printf (" \n");
|
printf (" \n");
|
||||||
printf (" -k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.\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");
|
printf (" Only supports NXDN, DMR Basic Privacy (decimal value). \n");
|
||||||
@@ -1610,7 +1678,7 @@
|
|||||||
printf (" -p Disable Tune to Private Calls (DMR TIII, P25, NXDN Type-C and Type-D)\n");
|
printf (" -p Disable Tune to Private Calls (DMR TIII, P25, NXDN Type-C and Type-D)\n");
|
||||||
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)\n");
|
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)\n");
|
||||||
printf (" -e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)\n");
|
printf (" -e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)\n");
|
||||||
printf (" (NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls \n");
|
printf (" (NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls) \n");
|
||||||
printf (" -I <dec> Specify TG to Hold During Trunking (DMR, P25, NXDN Type-C Trunking)\n");
|
printf (" -I <dec> Specify TG to Hold During Trunking (DMR, P25, NXDN Type-C Trunking)\n");
|
||||||
printf (" -U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)\n");
|
printf (" -U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)\n");
|
||||||
printf (" -B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n");
|
printf (" -B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n");
|
||||||
@@ -1898,7 +1966,7 @@
|
|||||||
|
|
||||||
exitflag = 0;
|
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+:j:")) != -1)
|
while ((c = getopt (argc, argv, "~haepPqs: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+:j:,:$:y:")) != -1)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
@@ -2017,6 +2085,30 @@
|
|||||||
baofeng_ap_pc5_keystream_creation(&state, optarg);
|
baofeng_ap_pc5_keystream_creation(&state, optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//Auctus (GoComm) Keystream Creation
|
||||||
|
case ',':
|
||||||
|
auctus_keystream_creation(&state, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//RAS Effective Key Creation
|
||||||
|
case '$':
|
||||||
|
ras_effective_key_creation(&state, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//RAS Effective Key Direct Set
|
||||||
|
case 'y':
|
||||||
|
sscanf (optarg, "%llX", &state.ras_effective_key);
|
||||||
|
state.ras_effective_key &= 0xFFFFFFFFFFFFFF; //truncate to 56-bits
|
||||||
|
ras_permute_order((state.ras_effective_key & 0xFFFFFFFF), state.ras_permutation_order);
|
||||||
|
fprintf (stderr,"DMR RAS 56-bit Effective Key: %llX\n", state.ras_effective_key);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Vertex Standard KS Generation
|
||||||
|
case 'u':
|
||||||
|
vertex_keystream_setup(&state, optarg);
|
||||||
|
state.keyloader = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
//Straight KS Generation
|
//Straight KS Generation
|
||||||
case 'S':
|
case 'S':
|
||||||
straight_mod_xor_keystream_creation(&state, optarg);
|
straight_mod_xor_keystream_creation(&state, optarg);
|
||||||
@@ -2027,10 +2119,11 @@
|
|||||||
fprintf (stderr,"DMRA Late Entry Encryption Identifiers Disabled\n");
|
fprintf (stderr,"DMRA Late Entry Encryption Identifiers Disabled\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'y': //use experimental 'float' audio output
|
//float audio experiment not going to be used going forward, very minimal benefit
|
||||||
opts.floating_point = 1; //enable floating point audio output
|
// case 'y': //use experimental 'float' audio output
|
||||||
fprintf (stderr,"Enabling Experimental Floating Point Audio Output\n");
|
// opts.floating_point = 1; //enable floating point audio output
|
||||||
break;
|
// fprintf (stderr,"Enabling Experimental Floating Point Audio Output\n");
|
||||||
|
// break;
|
||||||
|
|
||||||
case 'Y': //conventional scanner mode
|
case 'Y': //conventional scanner mode
|
||||||
opts.scanner_mode = 1; //enable scanner
|
opts.scanner_mode = 1; //enable scanner
|
||||||
@@ -2230,32 +2323,48 @@
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'H':
|
case 'H':
|
||||||
//new handling for 10/32/64 Char Key
|
//check for caltta bp key load
|
||||||
|
if (optarg[0] == 'C' && optarg[1] == ':')
|
||||||
strncpy(opts.szNumbers, optarg, 1023);
|
|
||||||
opts.szNumbers[1023] = '\0';
|
|
||||||
state.K1 = strtoull (opts.szNumbers, &pEnd, 16);
|
|
||||||
state.K2 = strtoull (pEnd, &pEnd, 16);
|
|
||||||
state.K3 = strtoull (pEnd, &pEnd, 16);
|
|
||||||
state.K4 = strtoull (pEnd, &pEnd, 16);
|
|
||||||
fprintf (stderr, "Hytera40/128/256 BP or AES128/256 Key = %016llX %016llX %016llX %016llX\n", state.K1, state.K2, state.K3, state.K4);
|
|
||||||
opts.dmr_mute_encL = 0;
|
|
||||||
opts.dmr_mute_encR = 0;
|
|
||||||
if (state.K1 == 0 && state.K2 == 0 && state.K3 == 0 && state.K4 == 0)
|
|
||||||
{
|
{
|
||||||
opts.dmr_mute_encL = 1;
|
caltta_bp_keystream_creation(&state, optarg+2);
|
||||||
opts.dmr_mute_encR = 1;
|
}
|
||||||
|
//check for Hytera OTA key load
|
||||||
|
else if (optarg[0] == 'O' && optarg[1] == ':')
|
||||||
|
{
|
||||||
|
hytera_ota_keystream_setup(&state, optarg+2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(opts.szNumbers, optarg, 1023);
|
||||||
|
opts.szNumbers[1023] = '\0';
|
||||||
|
state.K1 = strtoull (opts.szNumbers, &pEnd, 16);
|
||||||
|
state.K2 = strtoull (pEnd, &pEnd, 16);
|
||||||
|
state.K3 = strtoull (pEnd, &pEnd, 16);
|
||||||
|
state.K4 = strtoull (pEnd, &pEnd, 16);
|
||||||
|
if (state.K2 == 0 && state.K3 == 0 && state.K4 == 0)
|
||||||
|
fprintf (stderr, "Hytera BP 40-bit Key: %010llX\n", state.K1);
|
||||||
|
else if (state.K2 != 0)
|
||||||
|
fprintf (stderr, "Multi 128-bit Key: %016llX%016llX\n", state.K1, state.K2);
|
||||||
|
else
|
||||||
|
fprintf (stderr, "Multi 256-bit Key: %016llX%016llX%016llX%016llX\n", state.K1, state.K2, state.K3, state.K4);
|
||||||
|
opts.dmr_mute_encL = 0;
|
||||||
|
opts.dmr_mute_encR = 0;
|
||||||
|
if (state.K1 == 0 && state.K2 == 0 && state.K3 == 0 && state.K4 == 0)
|
||||||
|
{
|
||||||
|
opts.dmr_mute_encL = 1;
|
||||||
|
opts.dmr_mute_encR = 1;
|
||||||
|
}
|
||||||
|
state.H = state.K1; //shim still required?
|
||||||
|
//load the AES keys into a seperate handler
|
||||||
|
state.A1[0] = state.A1[1] = state.K1;
|
||||||
|
state.A2[0] = state.A2[1] = state.K2;
|
||||||
|
state.A3[0] = state.A3[1] = state.K3;
|
||||||
|
state.A4[0] = state.A4[1] = state.K4;
|
||||||
|
//disable keyloader function
|
||||||
|
state.keyloader = 0;
|
||||||
|
//signal an aes key is loaded into each slot -- if no value presented, then this won't matter anyways
|
||||||
|
state.aes_key_loaded[0] = state.aes_key_loaded[1] = 1;
|
||||||
}
|
}
|
||||||
state.H = state.K1; //shim still required?
|
|
||||||
//load the AES keys into a seperate handler
|
|
||||||
state.A1[0] = state.A1[1] = state.K1;
|
|
||||||
state.A2[0] = state.A2[1] = state.K2;
|
|
||||||
state.A3[0] = state.A3[1] = state.K3;
|
|
||||||
state.A4[0] = state.A4[1] = state.K4;
|
|
||||||
//disable keyloader function
|
|
||||||
state.keyloader = 0;
|
|
||||||
//signal an aes key is loaded into each slot -- if no value presented, then this won't matter anyways
|
|
||||||
state.aes_key_loaded[0] = state.aes_key_loaded[1] = 1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '4':
|
case '4':
|
||||||
@@ -3073,18 +3182,18 @@
|
|||||||
fprintf (stderr,"Enabling 6000 sps P25p2 all optimizations.\n");
|
fprintf (stderr,"Enabling 6000 sps P25p2 all optimizations.\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'u':
|
// case 'u':
|
||||||
sscanf (optarg, "%i", &opts.uvquality);
|
// sscanf (optarg, "%i", &opts.uvquality);
|
||||||
if (opts.uvquality < 1)
|
// if (opts.uvquality < 1)
|
||||||
{
|
// {
|
||||||
opts.uvquality = 1;
|
// opts.uvquality = 1;
|
||||||
}
|
// }
|
||||||
else if (opts.uvquality > 64)
|
// else if (opts.uvquality > 64)
|
||||||
{
|
// {
|
||||||
opts.uvquality = 64;
|
// opts.uvquality = 64;
|
||||||
}
|
// }
|
||||||
fprintf (stderr,"Setting unvoice speech quality to %i waves per band.\n", opts.uvquality);
|
// fprintf (stderr,"Setting unvoice speech quality to %i waves per band.\n", opts.uvquality);
|
||||||
break;
|
// break;
|
||||||
case 'x':
|
case 'x':
|
||||||
if (optarg[0] == 'x')
|
if (optarg[0] == 'x')
|
||||||
{
|
{
|
||||||
@@ -3218,9 +3327,24 @@
|
|||||||
if (curr != NULL) ; //continue
|
if (curr != NULL) ; //continue
|
||||||
else goto RTLEND; //end early with preset values
|
else goto RTLEND; //end early with preset values
|
||||||
|
|
||||||
curr = strtok(NULL, ":"); //rtl device number "-D"
|
if (strcmp (curr, "rtltcp") == 0) //rtl_tcp server instead of a local dongle
|
||||||
if (curr != NULL) opts.rtl_dev_index = atoi (curr);
|
{
|
||||||
else goto RTLEND;
|
opts.rtltcp_enabled = 1;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //rtl_tcp hostname
|
||||||
|
if (curr != NULL) snprintf (opts.rtltcp_hostname, sizeof(opts.rtltcp_hostname), "%s", curr);
|
||||||
|
else goto RTLEND;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //rtl_tcp port
|
||||||
|
if (curr != NULL) opts.rtltcp_portno = atoi (curr);
|
||||||
|
else goto RTLEND;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr = strtok(NULL, ":"); //rtl device number "-D"
|
||||||
|
if (curr != NULL) opts.rtl_dev_index = atoi (curr);
|
||||||
|
else goto RTLEND;
|
||||||
|
}
|
||||||
|
|
||||||
curr = strtok(NULL, ":"); //rtl freq "-c"
|
curr = strtok(NULL, ":"); //rtl freq "-c"
|
||||||
if (curr != NULL) opts.rtlsdr_center_freq = (uint32_t)atofs(curr);
|
if (curr != NULL) opts.rtlsdr_center_freq = (uint32_t)atofs(curr);
|
||||||
@@ -3263,6 +3387,8 @@
|
|||||||
|
|
||||||
RTLEND:
|
RTLEND:
|
||||||
|
|
||||||
|
if (opts.rtltcp_enabled == 1) goto RTLTCPEND; //no local dongle to look for
|
||||||
|
|
||||||
device_count = rtlsdr_get_device_count();
|
device_count = rtlsdr_get_device_count();
|
||||||
if (!device_count)
|
if (!device_count)
|
||||||
{
|
{
|
||||||
@@ -3290,10 +3416,15 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTLTCPEND:
|
||||||
|
|
||||||
if (opts.rtl_volume_multiplier > 3 || opts.rtl_volume_multiplier < 0)
|
if (opts.rtl_volume_multiplier > 3 || opts.rtl_volume_multiplier < 0)
|
||||||
opts.rtl_volume_multiplier = 1; //I wonder if you could flip polarity by using -1
|
opts.rtl_volume_multiplier = 1; //I wonder if you could flip polarity by using -1
|
||||||
|
|
||||||
fprintf (stderr, "Dev %d ", opts.rtl_dev_index);
|
if (opts.rtltcp_enabled == 1)
|
||||||
|
fprintf (stderr, "rtl_tcp %s:%d ", opts.rtltcp_hostname, opts.rtltcp_portno);
|
||||||
|
else
|
||||||
|
fprintf (stderr, "Dev %d ", opts.rtl_dev_index);
|
||||||
fprintf (stderr, "Freq %d ", opts.rtlsdr_center_freq);
|
fprintf (stderr, "Freq %d ", opts.rtlsdr_center_freq);
|
||||||
fprintf (stderr, "Gain %d ", opts.rtl_gain_value);
|
fprintf (stderr, "Gain %d ", opts.rtl_gain_value);
|
||||||
fprintf (stderr, "PPM %d ", opts.rtlsdr_ppm_error);
|
fprintf (stderr, "PPM %d ", opts.rtlsdr_ppm_error);
|
||||||
|
|||||||
224
src/dsd_mbe.c
224
src/dsd_mbe.c
@@ -304,9 +304,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
if (state->payload_algid == 0x9F) //DES-XL
|
if (state->payload_algid == 0x9F) //DES-XL
|
||||||
des_multi_keystream_output (state->payload_miP, state->R, state->ks_octetL, 2, state->xl_is_hdu); //hard coded bit count value, xl_is_hdu determines lfsr run values
|
des_multi_keystream_output (state->payload_miP, state->R, state->ks_octetL, 2, state->xl_is_hdu); //hard coded bit count value, xl_is_hdu determines lfsr run values
|
||||||
if (state->payload_algid == 0x84) //AES256
|
if (state->payload_algid == 0x84) //AES256
|
||||||
aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 2, 14); //14 + 1 discard round
|
aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 2, 16); //15 + 1 discard round
|
||||||
if (state->payload_algid == 0x89) //AES128
|
if (state->payload_algid == 0x89) //AES128
|
||||||
aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 0, 14); //14 + 1 discard round
|
aes_ofb_keystream_output (state->aes_iv, aes_key, state->ks_octetL, 0, 16); //15 + 1 discard round
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,7 +599,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
}
|
}
|
||||||
if (state->rkey_array[hash] != 0)
|
if (state->rkey_array[hash] != 0)
|
||||||
{
|
{
|
||||||
|
#ifdef VERTEX_KEY40_BY_TG
|
||||||
|
state->vtx40_key = state->rkey_array[hash] & 0xFFFFFFFFFF;
|
||||||
|
vertex_40_keystream_creation(state, state->vtx40_key);
|
||||||
|
#elif VERTEX_KEY256_BY_TG
|
||||||
|
//TODO: This
|
||||||
|
#else
|
||||||
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
|
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
|
||||||
|
#endif
|
||||||
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
||||||
opts->dmr_mute_encL = 0;
|
opts->dmr_mute_encL = 0;
|
||||||
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
|
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
|
||||||
@@ -619,72 +626,101 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (state->vtx_key_loaded != 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||||
|
(state->vtx_key_loaded != 0 && state->forced_alg_id == 1) )
|
||||||
|
{
|
||||||
|
if (memcmp(ambe_d, ambe_silence, 49) != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 49; i++)
|
||||||
|
{
|
||||||
|
if (i < 8 || i > 11)
|
||||||
|
ambe_d[i] ^= (char)state->static_ks_bits[0][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts->dmr_mute_encL = 0; //shim to unmute
|
||||||
|
}
|
||||||
|
|
||||||
|
//Hytera BP //TODO: Clean this mess up
|
||||||
if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
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->forced_alg_id == 1) )
|
||||||
{
|
{
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
unsigned long long int k1 = state->K1;
|
unsigned long long int k1 = state->K1;
|
||||||
unsigned long long int k2 = state->K2;
|
unsigned long long int k2 = state->K2;
|
||||||
unsigned long long int k3 = state->K3;
|
unsigned long long int k3 = state->K3;
|
||||||
unsigned long long int k4 = state->K4;
|
unsigned long long int k4 = state->K4;
|
||||||
|
|
||||||
int T_Key[256] = {0};
|
int T_Key[256] = {0};
|
||||||
int pN[882] = {0};
|
int pN[882] = {0};
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
if (k2 == 0)
|
if (k2 == 0)
|
||||||
{
|
|
||||||
len = 39;
|
|
||||||
k1 = k1 << 24;
|
|
||||||
}
|
|
||||||
if (k2 != 0)
|
|
||||||
{
|
|
||||||
len = 127;
|
|
||||||
}
|
|
||||||
if (k4 != 0)
|
|
||||||
{
|
|
||||||
len = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 64; i++)
|
|
||||||
{
|
|
||||||
T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 );
|
|
||||||
T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 );
|
|
||||||
T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 );
|
|
||||||
T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 );
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 882; i++)
|
|
||||||
{
|
|
||||||
pN[i] = T_Key[pos];
|
|
||||||
pos++;
|
|
||||||
if (pos > len)
|
|
||||||
{
|
{
|
||||||
pos = 0;
|
len = 39;
|
||||||
|
k1 = k1 << 24;
|
||||||
}
|
}
|
||||||
}
|
if (k2 != 0)
|
||||||
|
|
||||||
//sanity check
|
|
||||||
if (state->DMRvcL > 17) //18
|
|
||||||
{
|
|
||||||
state->DMRvcL = 17; //18
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = state->DMRvcL * 49;
|
|
||||||
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
|
||||||
pos += 49;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(i = 0; i < 49; i++)
|
|
||||||
{
|
{
|
||||||
ambe_d[i] ^= pN[pos];
|
len = 127;
|
||||||
|
}
|
||||||
|
if (k4 != 0)
|
||||||
|
{
|
||||||
|
len = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 );
|
||||||
|
T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 );
|
||||||
|
T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 );
|
||||||
|
T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 );
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 882; i++)
|
||||||
|
{
|
||||||
|
pN[i] = T_Key[pos];
|
||||||
pos++;
|
pos++;
|
||||||
|
if (pos > len)
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sanity check
|
||||||
|
if (state->DMRvcL > 17) //18
|
||||||
|
{
|
||||||
|
state->DMRvcL = 17; //18
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = state->DMRvcL * 49;
|
||||||
|
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||||
|
pos += 49;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(i = 0; i < 49; i++)
|
||||||
|
{
|
||||||
|
ambe_d[i] ^= pN[pos];
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->DMRvcL++;
|
||||||
}
|
}
|
||||||
state->DMRvcL++;
|
|
||||||
|
//Caltta BP
|
||||||
|
if ( (state->straight_ks == 0x26 && state->dmr_so & 0x40 && state->payload_algid == 0x26) || //&& state->payload_keyid != 0
|
||||||
|
(state->straight_ks == 0x26 && state->forced_alg_id == 0x26) )
|
||||||
|
{
|
||||||
|
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||||
|
state->static_ks_counter[state->currentslot] += 56;
|
||||||
|
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]++)%state->straight_mod] & 1); //Yikes!
|
||||||
|
state->static_ks_counter[state->currentslot] += 7;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//DMR and P25p2 DES-OFB 56 Handling, Slot 1, VCH 0 -- consider moving into the AES handler
|
//DMR and P25p2 DES-OFB 56 Handling, Slot 1, VCH 0 -- consider moving into the AES handler
|
||||||
@@ -743,8 +779,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
(state->currentslot == 0 && state->payload_algid == 0x25 && state->aes_key_loaded[0] == 1 ) || //DMR AES256
|
(state->currentslot == 0 && state->payload_algid == 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 == 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 == 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 >= 0x31 && \
|
||||||
(state->currentslot == 0 && state->payload_algid == 0x37 && state->aes_key_loaded[0] == 1 ) || //KIRI UNI
|
state->payload_algid <= 0x3A && state->aes_key_loaded[0] == 1 ) || //KIRI Any
|
||||||
(state->currentslot == 0 && state->payload_algid == 0x02 && state->R != 0 ) ) //HYT ENHANCED
|
(state->currentslot == 0 && state->payload_algid == 0x02 && state->R != 0 ) ) //HYT ENHANCED
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -777,19 +813,13 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
if(state->payload_algid == 0x02)
|
if(state->payload_algid == 0x02)
|
||||||
{
|
{
|
||||||
n = 0;
|
n = 0;
|
||||||
hytera_enhanced_rc4_setup(opts, state, state->R, state->payload_mi);
|
hytera_enhanced_rc4_setup(opts, state, state->R, state->payload_mi, 135);
|
||||||
}
|
}
|
||||||
if (state->payload_algid == 0x36)
|
if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A)
|
||||||
{
|
{
|
||||||
n = 0;
|
n = 0;
|
||||||
kirisun_adv_keystream_creation(state);
|
kirisun_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
|
//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
|
for (i = 0; i < 9 * 16; i++) //9 rounds at 16 octets
|
||||||
{
|
{
|
||||||
@@ -1016,6 +1046,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->payload_algid = 0;
|
state->payload_algid = 0;
|
||||||
for (int i = 0; i < 49; i++)
|
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!
|
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%state->straight_mod] & 1); //Yikes!
|
||||||
|
//apply optional discard (i.e., caltta bp)
|
||||||
|
if (state->straight_discard != 0)
|
||||||
|
state->static_ks_counter[state->currentslot] += state->straight_discard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1066,7 +1099,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
}
|
}
|
||||||
if (state->rkey_array[hash] != 0)
|
if (state->rkey_array[hash] != 0)
|
||||||
{
|
{
|
||||||
|
#ifdef VERTEX_KEY40_BY_TG
|
||||||
|
state->vtx40_key = state->rkey_array[hash] & 0xFFFFFFFFFF;
|
||||||
|
vertex_40_keystream_creation(state, state->vtx40_key);
|
||||||
|
#elif VERTEX_KEY256_BY_TG
|
||||||
|
//TODO: This
|
||||||
|
#else
|
||||||
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
|
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
|
||||||
|
#endif
|
||||||
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
||||||
opts->dmr_mute_encR = 0;
|
opts->dmr_mute_encR = 0;
|
||||||
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
|
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
|
||||||
@@ -1086,6 +1126,21 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (state->vtx_key_loaded != 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ||
|
||||||
|
(state->vtx_key_loaded != 0 && state->forced_alg_id == 1) )
|
||||||
|
{
|
||||||
|
if (memcmp(ambe_d, ambe_silence, 49) != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 49; i++)
|
||||||
|
{
|
||||||
|
if (i < 8 || i > 11)
|
||||||
|
ambe_d[i] ^= (char)state->static_ks_bits[1][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts->dmr_mute_encR = 0; //shim to unmute
|
||||||
|
}
|
||||||
|
|
||||||
|
//Hytera BP //TODO: Clean this mess up
|
||||||
if ( (state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ||
|
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->forced_alg_id == 1))
|
||||||
{
|
{
|
||||||
@@ -1154,6 +1209,20 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->DMRvcR++;
|
state->DMRvcR++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Caltta BP
|
||||||
|
if ( (state->straight_ks == 0x26 && state->dmr_soR & 0x40 && state->payload_algidR == 0x26) || //&& state->payload_keyidR != 0
|
||||||
|
(state->straight_ks == 0x26 && state->forced_alg_id == 0x26) )
|
||||||
|
{
|
||||||
|
if (memcmp(ambe_d, ambe_silence, 49) == 0)
|
||||||
|
state->static_ks_counter[state->currentslot] += 56;
|
||||||
|
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]++)%state->straight_mod] & 1); //Yikes!
|
||||||
|
state->static_ks_counter[state->currentslot] += 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//DMR and P25p2 DES-OFB 56 Handling, Slot 2, VCH 1 -- Consider moving into AES handler
|
//DMR and P25p2 DES-OFB 56 Handling, Slot 2, VCH 1 -- Consider moving into AES handler
|
||||||
if ( (state->currentslot == 1 && state->payload_algidR == 0x22 && state->RR != 0) ||
|
if ( (state->currentslot == 1 && state->payload_algidR == 0x22 && state->RR != 0) ||
|
||||||
(state->currentslot == 1 && state->payload_algidR == 0x81 && state->RR != 0) )
|
(state->currentslot == 1 && state->payload_algidR == 0x81 && state->RR != 0) )
|
||||||
@@ -1210,8 +1279,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
(state->currentslot == 1 && state->payload_algidR == 0x25 && state->aes_key_loaded[1] == 1 ) || //DMR AES256
|
(state->currentslot == 1 && state->payload_algidR == 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 == 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 == 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 >= 0x31 && \
|
||||||
(state->currentslot == 1 && state->payload_algidR == 0x37 && state->aes_key_loaded[1] == 1 ) || //KIRI UNI
|
state->payload_algidR <= 0x3A && state->aes_key_loaded[1] == 1 ) || //KIRI Any
|
||||||
(state->currentslot == 1 && state->payload_algidR == 0x02 && state->RR != 0 ) ) //HYT ENHANCED
|
(state->currentslot == 1 && state->payload_algidR == 0x02 && state->RR != 0 ) ) //HYT ENHANCED
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1244,19 +1313,13 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
if(state->payload_algidR == 0x02)
|
if(state->payload_algidR == 0x02)
|
||||||
{
|
{
|
||||||
n = 0;
|
n = 0;
|
||||||
hytera_enhanced_rc4_setup(opts, state, state->RR, state->payload_miR);
|
hytera_enhanced_rc4_setup(opts, state, state->RR, state->payload_miR, 135);
|
||||||
}
|
}
|
||||||
if (state->payload_algidR == 0x36)
|
if (state->payload_algidR >= 0x31 && state->payload_algidR <= 0x3A)
|
||||||
{
|
{
|
||||||
n = 0;
|
n = 0;
|
||||||
kirisun_adv_keystream_creation(state);
|
kirisun_keystream_creation(state);
|
||||||
}
|
}
|
||||||
if (state->payload_algidR == 0x37)
|
|
||||||
{
|
|
||||||
n = 0;
|
|
||||||
kirisun_uni_keystream_creation(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load Keystream Octet Bytes directly into keystream array
|
//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
|
for (i = 0; i < 9 * 16; i++) //9 rounds at 16 octets //TODO: Convert to unpack function
|
||||||
{
|
{
|
||||||
@@ -1482,6 +1545,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->payload_algidR = 0;
|
state->payload_algidR = 0;
|
||||||
for (int i = 0; i < 49; i++)
|
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!
|
ambe_d[i] ^= (uint8_t)(state->static_ks_bits[state->currentslot][(state->static_ks_counter[state->currentslot]++)%state->straight_mod] & 1); //Yikes!
|
||||||
|
//apply optional discard (i.e., caltta bp)
|
||||||
|
if (state->straight_discard != 0)
|
||||||
|
state->static_ks_counter[state->currentslot] += state->straight_discard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1538,6 +1604,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
if (state->ken_sc == 1)
|
if (state->ken_sc == 1)
|
||||||
state->dmr_encL = 0;
|
state->dmr_encL = 0;
|
||||||
|
|
||||||
|
if (state->payload_algid == 0x26 && state->straight_ks == 0x26)
|
||||||
|
state->dmr_encL = 0;
|
||||||
|
|
||||||
//reverse mute testing, only mute unencrypted traffic (slave piggyback dsd+ method)
|
//reverse mute testing, only mute unencrypted traffic (slave piggyback dsd+ method)
|
||||||
if (opts->reverse_mute == 1)
|
if (opts->reverse_mute == 1)
|
||||||
{
|
{
|
||||||
@@ -1618,6 +1687,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
if (state->ken_sc == 1)
|
if (state->ken_sc == 1)
|
||||||
state->dmr_encR = 0;
|
state->dmr_encR = 0;
|
||||||
|
|
||||||
|
if (state->payload_algidR == 0x26 && state->straight_ks == 0x26)
|
||||||
|
state->dmr_encR = 0;
|
||||||
|
|
||||||
//reverse mute testing, only mute unencrypted traffic (slave piggyback dsd+ method)
|
//reverse mute testing, only mute unencrypted traffic (slave piggyback dsd+ method)
|
||||||
if (opts->reverse_mute == 1)
|
if (opts->reverse_mute == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -244,7 +244,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (opts->audio_in_type == 3)
|
if (opts->audio_in_type == 3)
|
||||||
{
|
{
|
||||||
printw ("| RTL: %d;", opts->rtl_dev_index);
|
if (opts->rtltcp_enabled == 1)
|
||||||
|
printw ("| RTL_TCP: %s:%d;", opts->rtltcp_hostname, opts->rtltcp_portno);
|
||||||
|
else printw ("| RTL: %d;", opts->rtl_dev_index);
|
||||||
if (opts->rtl_gain_actual == -100)
|
if (opts->rtl_gain_actual == -100)
|
||||||
printw (" G: AGC;");
|
printw (" G: AGC;");
|
||||||
else
|
else
|
||||||
@@ -921,10 +923,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->dmr_is_ras == 1)
|
||||||
|
printw ("{RAS}");
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (lls == 32 || lls == 33 || lls == 34)
|
else if (lls == 32 || lls == 33 || lls == 34)
|
||||||
{
|
{
|
||||||
printw ("DMR MS - DCC: %02i; ", state->dmr_color_code);
|
printw ("DMR MS - DCC: %02i; ", state->dmr_color_code);
|
||||||
|
|
||||||
|
if (state->dmr_is_ras == 1)
|
||||||
|
printw ("{RAS}");
|
||||||
}
|
}
|
||||||
else if (lls == 0 || lls == 1) //P1
|
else if (lls == 0 || lls == 1) //P1
|
||||||
{
|
{
|
||||||
@@ -1104,6 +1112,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
||||||
attron(COLOR_PAIR(3));
|
attron(COLOR_PAIR(3));
|
||||||
}
|
}
|
||||||
|
if (state->payload_algid == 0x26)
|
||||||
|
{
|
||||||
|
attron(COLOR_PAIR(1));
|
||||||
|
printw("Caltta BP ");
|
||||||
|
// if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); } //TODO: This
|
||||||
|
attron(COLOR_PAIR(3));
|
||||||
|
}
|
||||||
if (state->payload_algid == 0x02)
|
if (state->payload_algid == 0x02)
|
||||||
{
|
{
|
||||||
attron(COLOR_PAIR(1));
|
attron(COLOR_PAIR(1));
|
||||||
@@ -1112,26 +1127,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
printw(" Key: %010llX", state->R);
|
printw(" Key: %010llX", state->R);
|
||||||
attron(COLOR_PAIR(3));
|
attron(COLOR_PAIR(3));
|
||||||
}
|
}
|
||||||
if (state->payload_algid == 0x36)
|
if (state->payload_algid >= 0x31 && state->payload_algid <= 0x3A)
|
||||||
{
|
{
|
||||||
attron(COLOR_PAIR(1));
|
attron(COLOR_PAIR(1));
|
||||||
printw("Kirisun Advanced ");
|
printw("Kirisun Encryption ");
|
||||||
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
if (state->aes_key_loaded[0] != 0) { printw("KS: %016llX ", state->A4[0]); }
|
||||||
attron(COLOR_PAIR(3));
|
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");
|
printw ("\n");
|
||||||
|
|
||||||
@@ -1299,6 +1301,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||||||
attron(COLOR_PAIR(3));
|
attron(COLOR_PAIR(3));
|
||||||
}
|
}
|
||||||
|
if (state->payload_algidR == 0x26)
|
||||||
|
{
|
||||||
|
attron(COLOR_PAIR(1));
|
||||||
|
printw("Caltta BP ");
|
||||||
|
// if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); } //TODO: This
|
||||||
|
attron(COLOR_PAIR(3));
|
||||||
|
}
|
||||||
if (state->payload_algidR == 0x02)
|
if (state->payload_algidR == 0x02)
|
||||||
{
|
{
|
||||||
attron(COLOR_PAIR(1));
|
attron(COLOR_PAIR(1));
|
||||||
@@ -1307,26 +1316,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
printw(" Key: %010llX", state->RR);
|
printw(" Key: %010llX", state->RR);
|
||||||
attron(COLOR_PAIR(3));
|
attron(COLOR_PAIR(3));
|
||||||
}
|
}
|
||||||
if (state->payload_algidR == 0x36)
|
if (state->payload_algidR >= 0x31 && state->payload_algidR <= 0x3A)
|
||||||
{
|
{
|
||||||
attron(COLOR_PAIR(1));
|
attron(COLOR_PAIR(1));
|
||||||
printw("Kirisun Advanced ");
|
printw("Kirisun Advanced ");
|
||||||
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
if (state->aes_key_loaded[1] != 0) { printw("KS: %016llX ", state->A4[1]); }
|
||||||
attron(COLOR_PAIR(3));
|
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");
|
printw ("\n");
|
||||||
|
|
||||||
|
|||||||
@@ -314,3 +314,25 @@ rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword) {
|
|||||||
}
|
}
|
||||||
return &rs_12_9_checksum;
|
return &rs_12_9_checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//This will run a RS 12,9 encode on 9 bytes of input
|
||||||
|
//input is an array of 12 bytes or more
|
||||||
|
void rs_12_9_encode(uint8_t * input)
|
||||||
|
{
|
||||||
|
rs_12_9_codeword_t cw;
|
||||||
|
rs_12_9_checksum_t *cs;
|
||||||
|
|
||||||
|
//init cw
|
||||||
|
memset(cw.data, 0, 12*sizeof(uint8_t));
|
||||||
|
|
||||||
|
//Copy 9 bytes of data input
|
||||||
|
memcpy(cw.data, input, 9);
|
||||||
|
|
||||||
|
//Calculate the 3 parity / checksum bytes
|
||||||
|
cs = rs_12_9_calc_checksum(&cw);
|
||||||
|
|
||||||
|
//Build the final 12-byte codeword
|
||||||
|
input[9] = cs->bytes[0];
|
||||||
|
input[10] = cs->bytes[1];
|
||||||
|
input[11] = cs->bytes[2];
|
||||||
|
}
|
||||||
|
|||||||
123
src/rs-16-13.c
Normal file
123
src/rs-16-13.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* RS(16,13) encoder
|
||||||
|
*
|
||||||
|
* 13 data bytes + 3 parity bytes = 16-byte codeword
|
||||||
|
*
|
||||||
|
* Uses the same generator polynomial and GF(256) tables as the
|
||||||
|
* DMR RS(12,9) implementation (DMR AI Spec / dmrshark / dsd):
|
||||||
|
*
|
||||||
|
* g(x) = x^3 + 0x40 x^2 + 0x38 x + 0x0e
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* Constants
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
#define RS_DATASIZE 13
|
||||||
|
#define RS_CHECKSUMSIZE 3
|
||||||
|
#define RS_CODEWORDSIZE (RS_DATASIZE + RS_CHECKSUMSIZE) /* 16 */
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* Galois Field tables (GF(256) – same as DMR RS(12,9))
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
static const uint8_t galois_exp_table[256] = {
|
||||||
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1D, 0x3A, 0x74, 0xE8, 0xCD, 0x87, 0x13, 0x26,
|
||||||
|
0x4C, 0x98, 0x2D, 0x5A, 0xB4, 0x75, 0xEA, 0xC9, 0x8F, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0,
|
||||||
|
0x9D, 0x27, 0x4E, 0x9C, 0x25, 0x4A, 0x94, 0x35, 0x6A, 0xD4, 0xB5, 0x77, 0xEE, 0xC1, 0x9F, 0x23,
|
||||||
|
0x46, 0x8C, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x5D, 0xBA, 0x69, 0xD2, 0xB9, 0x6F, 0xDE, 0xA1,
|
||||||
|
0x5F, 0xBE, 0x61, 0xC2, 0x99, 0x2F, 0x5E, 0xBC, 0x65, 0xCA, 0x89, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
|
||||||
|
0xFD, 0xE7, 0xD3, 0xBB, 0x6B, 0xD6, 0xB1, 0x7F, 0xFE, 0xE1, 0xDF, 0xA3, 0x5B, 0xB6, 0x71, 0xE2,
|
||||||
|
0xD9, 0xAF, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xBD, 0x67, 0xCE,
|
||||||
|
0x81, 0x1F, 0x3E, 0x7C, 0xF8, 0xED, 0xC7, 0x93, 0x3B, 0x76, 0xEC, 0xC5, 0x97, 0x33, 0x66, 0xCC,
|
||||||
|
0x85, 0x17, 0x2E, 0x5C, 0xB8, 0x6D, 0xDA, 0xA9, 0x4F, 0x9E, 0x21, 0x42, 0x84, 0x15, 0x2A, 0x54,
|
||||||
|
0xA8, 0x4D, 0x9A, 0x29, 0x52, 0xA4, 0x55, 0xAA, 0x49, 0x92, 0x39, 0x72, 0xE4, 0xD5, 0xB7, 0x73,
|
||||||
|
0xE6, 0xD1, 0xBF, 0x63, 0xC6, 0x91, 0x3F, 0x7E, 0xFC, 0xE5, 0xD7, 0xB3, 0x7B, 0xF6, 0xF1, 0xFF,
|
||||||
|
0xE3, 0xDB, 0xAB, 0x4B, 0x96, 0x31, 0x62, 0xC4, 0x95, 0x37, 0x6E, 0xDC, 0xA5, 0x57, 0xAE, 0x41,
|
||||||
|
0x82, 0x19, 0x32, 0x64, 0xC8, 0x8D, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xDD, 0xA7, 0x53, 0xA6,
|
||||||
|
0x51, 0xA2, 0x59, 0xB2, 0x79, 0xF2, 0xF9, 0xEF, 0xC3, 0x9B, 0x2B, 0x56, 0xAC, 0x45, 0x8A, 0x09,
|
||||||
|
0x12, 0x24, 0x48, 0x90, 0x3D, 0x7A, 0xF4, 0xF5, 0xF7, 0xF3, 0xFB, 0xEB, 0xCB, 0x8B, 0x0B, 0x16,
|
||||||
|
0x2C, 0x58, 0xB0, 0x7D, 0xFA, 0xE9, 0xCF, 0x83, 0x1B, 0x36, 0x6C, 0xD8, 0xAD, 0x47, 0x8E, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t galois_log_table[256] = {
|
||||||
|
0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75,
|
||||||
|
4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
|
||||||
|
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69,
|
||||||
|
29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166,
|
||||||
|
6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
|
||||||
|
54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64,
|
||||||
|
30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
|
||||||
|
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87,
|
||||||
|
7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
|
||||||
|
227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
|
||||||
|
55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97,
|
||||||
|
242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162,
|
||||||
|
31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246,
|
||||||
|
108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90,
|
||||||
|
203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
|
||||||
|
79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* Galois multiplication
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
static uint8_t galois_mult(uint8_t a, uint8_t b)
|
||||||
|
{
|
||||||
|
if (a == 0 || b == 0)
|
||||||
|
return 0;
|
||||||
|
return galois_exp_table[(galois_log_table[a] + galois_log_table[b]) % 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* RS(16,13) encoder – LFSR with the DMR generator polynomial
|
||||||
|
*
|
||||||
|
* genpoly coefficients (same as RS(12,9)):
|
||||||
|
* { 0x40, 0x38, 0x0e, 0x01 }
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
void rs16_13_encode(const uint8_t data_in[RS_DATASIZE], uint8_t codeword[RS_CODEWORDSIZE])
|
||||||
|
{
|
||||||
|
/* Generator polynomial coefficients from DMR AI Spec */
|
||||||
|
static const uint8_t genpoly[] = { 0x40, 0x38, 0x0e, 0x01 };
|
||||||
|
|
||||||
|
uint8_t parity[3] = { 0, 0, 0 };
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t feedback;
|
||||||
|
|
||||||
|
for (i = 0; i < RS_DATASIZE; i++) {
|
||||||
|
feedback = data_in[i] ^ parity[0];
|
||||||
|
|
||||||
|
parity[0] = parity[1] ^ galois_mult(genpoly[2], feedback);
|
||||||
|
parity[1] = parity[2] ^ galois_mult(genpoly[1], feedback);
|
||||||
|
parity[2] = galois_mult(genpoly[0], feedback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build systematic codeword: data || parity */
|
||||||
|
memcpy(codeword, data_in, RS_DATASIZE);
|
||||||
|
codeword[13] = parity[0];
|
||||||
|
codeword[14] = parity[1];
|
||||||
|
codeword[15] = parity[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
//This will run a RS 16,13 encode on 13 bytes of input
|
||||||
|
//input is an array of 16 bytes or more
|
||||||
|
void rs_16_13_encode(uint8_t * input)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t output[16];
|
||||||
|
memset(output, 0, sizeof(output));
|
||||||
|
|
||||||
|
//Calculate the 3 parity / checksum bytes
|
||||||
|
rs16_13_encode(input, output);
|
||||||
|
|
||||||
|
//append the encoded parity to the input
|
||||||
|
input[13] = output[13];
|
||||||
|
input[14] = output[14];
|
||||||
|
input[15] = output[15];
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ static int atan_lut_size = 131072; /* 512 KB */
|
|||||||
static int atan_lut_coef = 8;
|
static int atan_lut_coef = 8;
|
||||||
|
|
||||||
//UDP -- keep for compatibility reasons
|
//UDP -- keep for compatibility reasons
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
static pthread_t socket_freq;
|
static pthread_t socket_freq;
|
||||||
@@ -453,6 +454,9 @@ void dc_block_filter(struct demod_state *fm)
|
|||||||
{
|
{
|
||||||
int i, avg;
|
int i, avg;
|
||||||
int64_t sum = 0;
|
int64_t sum = 0;
|
||||||
|
if (fm->result_len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (i=0; i < fm->result_len; i++) {
|
for (i=0; i < fm->result_len; i++) {
|
||||||
sum += fm->result[i];
|
sum += fm->result[i];
|
||||||
}
|
}
|
||||||
@@ -567,7 +571,7 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
|||||||
static void *dongle_thread_fn(void *arg)
|
static void *dongle_thread_fn(void *arg)
|
||||||
{
|
{
|
||||||
struct dongle_state *s = static_cast<dongle_state*>(arg);
|
struct dongle_state *s = static_cast<dongle_state*>(arg);
|
||||||
rtlsdr_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len);
|
rtlsdr_or_tcp_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,17 +608,17 @@ int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
|
|||||||
{
|
{
|
||||||
int i, r, err1, err2, count, nearest;
|
int i, r, err1, err2, count, nearest;
|
||||||
int* gains;
|
int* gains;
|
||||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
r = rtlsdr_or_tcp_set_tuner_gain_mode(dev, 1);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
count = rtlsdr_get_tuner_gains(dev, NULL);
|
count = rtlsdr_or_tcp_get_tuner_gains(dev, NULL);
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
gains = static_cast<int*>(malloc(sizeof(int) * count));
|
gains = static_cast<int*>(malloc(sizeof(int) * count));
|
||||||
count = rtlsdr_get_tuner_gains(dev, gains);
|
count = rtlsdr_or_tcp_get_tuner_gains(dev, gains);
|
||||||
nearest = gains[0];
|
nearest = gains[0];
|
||||||
for (i=0; i<count; i++) {
|
for (i=0; i<count; i++) {
|
||||||
err1 = abs(target_gain - nearest);
|
err1 = abs(target_gain - nearest);
|
||||||
@@ -629,20 +633,28 @@ int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
|
|||||||
|
|
||||||
int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
||||||
{
|
{
|
||||||
int r;
|
int r = -1;
|
||||||
r = rtlsdr_set_center_freq(dev, frequency);
|
|
||||||
if (r < 0) {
|
//spam tuning
|
||||||
fprintf (stderr, " (WARNING: Failed to set Center Frequency). \n");
|
for (int i = 0; i < 20; i++)
|
||||||
} else {
|
{
|
||||||
fprintf (stderr, " (Center Frequency: %u Hz.) \n", frequency);
|
r = rtlsdr_or_tcp_set_center_freq(dev, frequency);
|
||||||
|
if (r < 0)
|
||||||
|
fprintf (stderr, " (RETRY: Failed to set Center Frequency %u). \n", dongle.freq);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, " (Center Frequency: %u Hz.) \n", frequency);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_sample_rate(dev, samp_rate);
|
r = rtlsdr_or_tcp_set_sample_rate(dev, samp_rate);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set sample rate.\n");
|
fprintf (stderr, "WARNING: Failed to set sample rate.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -654,7 +666,7 @@ int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
|||||||
int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_direct_sampling(dev, on);
|
r = rtlsdr_or_tcp_set_direct_sampling(dev, on);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set direct sampling mode.\n");
|
fprintf (stderr, "WARNING: Failed to set direct sampling mode.\n");
|
||||||
return r;
|
return r;
|
||||||
@@ -671,7 +683,7 @@ int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
|||||||
int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_offset_tuning(dev, 1);
|
r = rtlsdr_or_tcp_set_offset_tuning(dev, 1);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set offset tuning.\n");
|
fprintf (stderr, "WARNING: Failed to set offset tuning.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -683,7 +695,7 @@ int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
|||||||
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
r = rtlsdr_or_tcp_set_tuner_gain_mode(dev, 0);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -695,12 +707,12 @@ int verbose_auto_gain(rtlsdr_dev_t *dev)
|
|||||||
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
r = rtlsdr_or_tcp_set_tuner_gain_mode(dev, 1);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
r = rtlsdr_set_tuner_gain(dev, gain);
|
r = rtlsdr_or_tcp_set_tuner_gain(dev, gain);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -714,7 +726,7 @@ int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
|||||||
int r;
|
int r;
|
||||||
// if (ppm_error == 0) {
|
// if (ppm_error == 0) {
|
||||||
// return 0;}
|
// return 0;}
|
||||||
r = rtlsdr_set_freq_correction(dev, ppm_error);
|
r = rtlsdr_or_tcp_set_freq_correction(dev, ppm_error);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set ppm error.\n");
|
fprintf (stderr, "WARNING: Failed to set ppm error.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -726,7 +738,7 @@ int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
|||||||
int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_reset_buffer(dev);
|
r = rtlsdr_or_tcp_reset_buffer(dev);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to reset buffers.\n");}
|
fprintf (stderr, "WARNING: Failed to reset buffers.\n");}
|
||||||
return r;
|
return r;
|
||||||
@@ -799,7 +811,7 @@ static void *controller_thread_fn(void *arg)
|
|||||||
/* hacky hopping */
|
/* hacky hopping */
|
||||||
s->freq_now = (s->freq_now + 1) % s->freq_len;
|
s->freq_now = (s->freq_now + 1) % s->freq_len;
|
||||||
optimal_settings(s->freqs[s->freq_now], demod.rate_in);
|
optimal_settings(s->freqs[s->freq_now], demod.rate_in);
|
||||||
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
rtlsdr_or_tcp_set_center_freq(dongle.dev, dongle.freq);
|
||||||
dongle.mute = BUFFER_DUMP;
|
dongle.mute = BUFFER_DUMP;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1004,7 +1016,7 @@ static void *socket_thread_fn(void *arg) {
|
|||||||
new_freq = chars_to_int(buffer);
|
new_freq = chars_to_int(buffer);
|
||||||
dongle.freq = new_freq;
|
dongle.freq = new_freq;
|
||||||
optimal_settings(new_freq, demod.rate_in);
|
optimal_settings(new_freq, demod.rate_in);
|
||||||
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
rtlsdr_or_tcp_set_center_freq(dongle.dev, dongle.freq);
|
||||||
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
|
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,7 +1031,7 @@ static void *socket_thread_fn(void *arg) {
|
|||||||
void rtlsdr_sighandler()
|
void rtlsdr_sighandler()
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Signal caught, exiting!\n");
|
fprintf (stderr, "Signal caught, exiting!\n");
|
||||||
rtlsdr_cancel_async(dongle.dev);
|
rtlsdr_or_tcp_cancel_async(dongle.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_rtlsdr_stream(dsd_opts *opts)
|
void open_rtlsdr_stream(dsd_opts *opts)
|
||||||
@@ -1072,14 +1084,23 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
|||||||
|
|
||||||
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
|
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
|
||||||
|
|
||||||
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
if (opts->rtltcp_enabled == 1)
|
||||||
if (r < 0)
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
|
if (rtltcp_open(opts->rtltcp_hostname, opts->rtltcp_portno) < 0)
|
||||||
exit(1);
|
//rtltcp_open prints its own error messages
|
||||||
} else {
|
exit(1);
|
||||||
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (demod.deemph) {
|
if (demod.deemph) {
|
||||||
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
|
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
|
||||||
@@ -1111,7 +1132,7 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
|||||||
void cleanup_rtlsdr_stream()
|
void cleanup_rtlsdr_stream()
|
||||||
{
|
{
|
||||||
fprintf (stderr, "cleaning up...\n");
|
fprintf (stderr, "cleaning up...\n");
|
||||||
rtlsdr_cancel_async(dongle.dev);
|
rtlsdr_or_tcp_cancel_async(dongle.dev);
|
||||||
pthread_join(dongle.thread, NULL);
|
pthread_join(dongle.thread, NULL);
|
||||||
safe_cond_signal(&demod.ready, &demod.ready_m);
|
safe_cond_signal(&demod.ready, &demod.ready_m);
|
||||||
pthread_join(demod.thread, NULL);
|
pthread_join(demod.thread, NULL);
|
||||||
@@ -1124,7 +1145,7 @@ void cleanup_rtlsdr_stream()
|
|||||||
output_cleanup(&output);
|
output_cleanup(&output);
|
||||||
controller_cleanup(&controller);
|
controller_cleanup(&controller);
|
||||||
|
|
||||||
rtlsdr_close(dongle.dev);
|
rtlsdr_or_tcp_close(dongle.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
//original for safe keeping
|
//original for safe keeping
|
||||||
@@ -1149,7 +1170,15 @@ int get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
|||||||
if (opts->rtlsdr_ppm_error != dongle.ppm_error)
|
if (opts->rtlsdr_ppm_error != dongle.ppm_error)
|
||||||
{
|
{
|
||||||
dongle.ppm_error = opts->rtlsdr_ppm_error;
|
dongle.ppm_error = opts->rtlsdr_ppm_error;
|
||||||
verbose_ppm_set(dongle.dev, dongle.ppm_error);
|
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int r = -1;
|
||||||
|
r = verbose_ppm_set(dongle.dev, dongle.ppm_error);
|
||||||
|
if (r < 0)
|
||||||
|
fprintf (stderr, " Retry Gain.");
|
||||||
|
else break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if Gain or AGC Value is Manually Changed, Change it here now
|
//if Gain or AGC Value is Manually Changed, Change it here now
|
||||||
@@ -1157,7 +1186,15 @@ int get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
dongle.gain = (opts->rtl_gain_value * 10);
|
dongle.gain = (opts->rtl_gain_value * 10);
|
||||||
opts->rtl_gain_actual = dongle.gain = nearest_gain(dongle.dev, dongle.gain);
|
opts->rtl_gain_actual = dongle.gain = nearest_gain(dongle.dev, dongle.gain);
|
||||||
verbose_gain_set(dongle.dev, dongle.gain);
|
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int r = -1;
|
||||||
|
r = verbose_gain_set(dongle.dev, dongle.gain);
|
||||||
|
if (r < 0)
|
||||||
|
fprintf (stderr, " Retry Gain.");
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
//debug
|
//debug
|
||||||
// fprintf (stderr, "\n Dongle Gain Set: %d; \n", dongle.gain);
|
// fprintf (stderr, "\n Dongle Gain Set: %d; \n", dongle.gain);
|
||||||
@@ -1166,7 +1203,15 @@ int get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
|||||||
else if (opts->rtl_gain_value == 0 && dongle.gain != AUTO_GAIN)
|
else if (opts->rtl_gain_value == 0 && dongle.gain != AUTO_GAIN)
|
||||||
{
|
{
|
||||||
opts->rtl_gain_actual = dongle.gain = AUTO_GAIN;
|
opts->rtl_gain_actual = dongle.gain = AUTO_GAIN;
|
||||||
verbose_auto_gain(dongle.dev);
|
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int r = 1;
|
||||||
|
r = verbose_auto_gain(dongle.dev);
|
||||||
|
if (r < 0)
|
||||||
|
fprintf (stderr, " Retry Gain.");
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
//debug
|
//debug
|
||||||
// fprintf (stderr, "\n AGC Set; \n");
|
// fprintf (stderr, "\n AGC Set; \n");
|
||||||
@@ -1197,16 +1242,23 @@ int get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
|||||||
//function may lag since it isn't running as its own thread
|
//function may lag since it isn't running as its own thread
|
||||||
void rtl_dev_tune(dsd_opts * opts, long int frequency)
|
void rtl_dev_tune(dsd_opts * opts, long int frequency)
|
||||||
{
|
{
|
||||||
int r;
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
fprintf (stderr, "\nTuning to %lu Hz.", frequency);
|
fprintf (stderr, "\nTuning to %lu Hz.", frequency);
|
||||||
dongle.freq = opts->rtlsdr_center_freq = frequency;
|
dongle.freq = opts->rtlsdr_center_freq = frequency;
|
||||||
optimal_settings(dongle.freq, demod.rate_in);
|
optimal_settings(dongle.freq, demod.rate_in); //this too?
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
fprintf (stderr, " (Center Frequency: %u Hz.) \n", dongle.freq);
|
fprintf (stderr, " (Center Frequency: %u Hz.) \n", dongle.freq);
|
||||||
r = rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
|
||||||
if (r < 0)
|
//spam tuning
|
||||||
fprintf (stderr, " (WARNING: Failed to set Center Frequency %u). \n", dongle.freq);
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int r = -1;
|
||||||
|
r = rtlsdr_or_tcp_set_center_freq(dongle.dev, dongle.freq);
|
||||||
|
if (r < 0)
|
||||||
|
fprintf (stderr, " (RETRY: Failed to set Center Frequency %u). \n", dongle.freq);
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_rwlock_wrlock(&output.rw); //prevent possible segfault when cleaning the queue
|
pthread_rwlock_wrlock(&output.rw); //prevent possible segfault when cleaning the queue
|
||||||
rtl_clean_queue();
|
rtl_clean_queue();
|
||||||
|
|||||||
331
src/rtl_sdr_tcp.c
Normal file
331
src/rtl_sdr_tcp.c
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* rtl_sdr_tcp.c
|
||||||
|
* rtl_tcp client for the RTL-SDR input: samples arrive on a TCP socket, and tuner commands are sent back on it
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
//MSG_NOSIGNAL is missing before macOS 11; SO_NOSIGPIPE in rtltcp_open keeps send from raising SIGPIPE there
|
||||||
|
#ifndef MSG_NOSIGNAL
|
||||||
|
#define MSG_NOSIGNAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//rtlsdr_read_async's default block size, in bytes
|
||||||
|
#define RTLTCP_BUF_LENGTH (16 * 32 * 512)
|
||||||
|
|
||||||
|
//rtl_tcp state: socket, tuner type, and a mutex that keeps commands from different threads from interleaving
|
||||||
|
//NOTE: Keeping these as static global is not great. They really should be in some kind of opaque handle
|
||||||
|
// like rtl_tcp_dev_t or something. For applications that only use one device at a time, this is fine.
|
||||||
|
// But if we ever move to supporting multiple simultaneous RTL tuners, this will need to change.
|
||||||
|
static int rtltcp_sock = -1;
|
||||||
|
static int rtltcp_tuner_type = RTLSDR_TUNER_UNKNOWN; //from the server's greeting
|
||||||
|
static pthread_mutex_t rtltcp_m = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
//limit for connecting to each address, reading the greeting, and sending a command, so a stalled server can't hang dsd-fme
|
||||||
|
static const int RTLTCP_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
static int64_t rtltcp_now_ms(void)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Poll in short intervals so shutdown works even when the server stops responding.
|
||||||
|
//A negative deadline permits an idle sample stream; setup and commands have fixed deadlines.
|
||||||
|
static int rtltcp_wait(int sock, short events, int64_t deadline)
|
||||||
|
{
|
||||||
|
struct pollfd pfd = {sock, events, 0};
|
||||||
|
while (!exitflag) {
|
||||||
|
int timeout = 100;
|
||||||
|
if (deadline >= 0) {
|
||||||
|
//check if we have exceeded our wait time
|
||||||
|
int64_t remaining = deadline - rtltcp_now_ms();
|
||||||
|
if (remaining <= 0) {
|
||||||
|
errno = ETIMEDOUT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//set the next poll timeout
|
||||||
|
if (remaining < timeout) timeout = (int)remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
//poll and handle the result
|
||||||
|
int r = poll(&pfd, 1, timeout);
|
||||||
|
if (r > 0) return 0; //recv/send/getsockopt will report EOF or socket errors
|
||||||
|
if (r < 0 && errno != EINTR) return -1;
|
||||||
|
}
|
||||||
|
errno = EINTR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtl_tcp command bytes, each named after the librtlsdr function the server calls with the parameter
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RTLTCP_SET_CENTER_FREQ = 0x01,
|
||||||
|
RTLTCP_SET_SAMPLE_RATE = 0x02,
|
||||||
|
RTLTCP_SET_TUNER_GAIN_MODE = 0x03,
|
||||||
|
RTLTCP_SET_TUNER_GAIN = 0x04,
|
||||||
|
RTLTCP_SET_FREQ_CORRECTION = 0x05,
|
||||||
|
RTLTCP_SET_DIRECT_SAMPLING = 0x09,
|
||||||
|
RTLTCP_SET_OFFSET_TUNING = 0x0a
|
||||||
|
};
|
||||||
|
|
||||||
|
//send one rtl_tcp command: a command byte followed by a 32-bit big-endian parameter.
|
||||||
|
//A partly sent command would misalign every later one, so a failed send ends the connection.
|
||||||
|
static int rtltcp_command(uint8_t cmd, uint32_t param)
|
||||||
|
{
|
||||||
|
//encode command and parameter to send to rtl_tcp
|
||||||
|
unsigned char buf[5] = {cmd, (unsigned char)(param >> 24), (unsigned char)(param >> 16), (unsigned char)(param >> 8), (unsigned char)param};
|
||||||
|
|
||||||
|
size_t sent = 0;
|
||||||
|
pthread_mutex_lock(&rtltcp_m);
|
||||||
|
|
||||||
|
//non-blocking send with a timeout
|
||||||
|
int64_t deadline = rtltcp_now_ms() + RTLTCP_TIMEOUT_MS;
|
||||||
|
while (sent < 5) {
|
||||||
|
if (rtltcp_wait(rtltcp_sock, POLLOUT, deadline) < 0) break;
|
||||||
|
ssize_t n = send(rtltcp_sock, buf + sent, 5 - sent, MSG_NOSIGNAL);
|
||||||
|
if (n < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (n <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sent += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//a failed or partial send ends the connection
|
||||||
|
if (sent < 5) {
|
||||||
|
shutdown(rtltcp_sock, SHUT_RDWR);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&rtltcp_m);
|
||||||
|
return sent < 5 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect to an rtl_tcp server over IPv4 or IPv6, read its greeting, and store the socket in rtltcp_sock; prints the outcome and returns 0, or -1 on failure
|
||||||
|
int rtltcp_open(const char *hostname, int portno)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res, *ai;
|
||||||
|
char portstr[16];
|
||||||
|
unsigned char header[12];
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
snprintf(portstr, sizeof(portstr), "%d", portno);
|
||||||
|
if (getaddrinfo(hostname, portstr, &hints, &res) != 0) {
|
||||||
|
fprintf (stderr, "Failed to resolve rtl_tcp server %s.\n", hostname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try each resolved address in turn until one connects
|
||||||
|
for (ai = res; ai != NULL && !exitflag; ai = ai->ai_next) {
|
||||||
|
//socket creation
|
||||||
|
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
|
if (sock < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set nonblocking
|
||||||
|
int flags = fcntl(sock, F_GETFL, 0);
|
||||||
|
if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
|
close(sock);
|
||||||
|
sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect
|
||||||
|
int r = connect(sock, ai->ai_addr, ai->ai_addrlen);
|
||||||
|
|
||||||
|
//connect returns immediately; wait for the attempt to finish, then SO_ERROR says whether it succeeded
|
||||||
|
if (r < 0 && errno == EINPROGRESS && rtltcp_wait(sock, POLLOUT, rtltcp_now_ms() + RTLTCP_TIMEOUT_MS) == 0) {
|
||||||
|
int error = 0;
|
||||||
|
socklen_t len = sizeof(error);
|
||||||
|
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error == 0) r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//successful connection
|
||||||
|
if (r == 0 && !exitflag) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//close socket and retry with different address
|
||||||
|
close(sock);
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
if (sock < 0) {
|
||||||
|
fprintf (stderr, "Failed to connect to rtl_tcp server %s:%d.\n", hostname, portno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
//macOS and the BSDs: a send to a closed connection returns an error instead of raising SIGPIPE
|
||||||
|
int one = 1;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t received = 0;
|
||||||
|
|
||||||
|
//non-blocking receive with a timeout
|
||||||
|
int64_t deadline = rtltcp_now_ms() + RTLTCP_TIMEOUT_MS;
|
||||||
|
while (received < sizeof(header)) {
|
||||||
|
if (rtltcp_wait(sock, POLLIN, deadline) < 0) break;
|
||||||
|
ssize_t n = recv(sock, header + received, sizeof(header) - received, 0);
|
||||||
|
if (n < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) continue;
|
||||||
|
if (n <= 0) break;
|
||||||
|
received += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//the greeting is "RTL0", the tuner type, and the number of tuner gain steps
|
||||||
|
if (received != sizeof(header) || memcmp(header, "RTL0", 4) != 0) {
|
||||||
|
fprintf (stderr, "%s:%d did not send an rtl_tcp greeting.\n", hostname, portno);
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//socket is valid and ready to use
|
||||||
|
rtltcp_sock = sock;
|
||||||
|
|
||||||
|
//store tuner type for later use in rtltcp_get_tuner_gains
|
||||||
|
rtltcp_tuner_type = ((uint32_t)header[4] << 24) | ((uint32_t)header[5] << 16) | ((uint32_t)header[6] << 8) | header[7];
|
||||||
|
fprintf (stderr, "Using rtl_tcp server %s:%d. \n", hostname, portno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtlsdr_get_tuner_gains for the server's tuner: copies its gain steps, in tenths of a dB, into gains unless gains is NULL, and returns the number of steps
|
||||||
|
static int rtltcp_get_tuner_gains(int *gains)
|
||||||
|
{
|
||||||
|
//rtl_tcp advertises only the gain count, not the values; librtlsdr's gain query requires a local device.
|
||||||
|
//Unfortunately this means we have to copy librtlsdr's tables here to select the nearest valid gain given the remote device.
|
||||||
|
//It would be better if rtl_tcp told us the actual list of supported gains, but it doesn't.
|
||||||
|
static const int e4k[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, 240, 290, 340, 420 };
|
||||||
|
static const int fc0012[] = { -99, -40, 71, 179, 192 };
|
||||||
|
static const int fc0013[] = { -99, -73, -65, -63, -60, -58, -54, 58, 61, 63, 65, 67, 68, 70, 71, 179, 181, 182, 184, 186, 188, 191, 197 };
|
||||||
|
static const int r82xx[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, 445, 480, 496 };
|
||||||
|
static const int none[] = { 0 };
|
||||||
|
const int *table = none;
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
//different tuners have different possible gains
|
||||||
|
switch (rtltcp_tuner_type) {
|
||||||
|
case RTLSDR_TUNER_E4000: table = e4k; count = sizeof(e4k) / sizeof(int); break;
|
||||||
|
case RTLSDR_TUNER_FC0012: table = fc0012; count = sizeof(fc0012) / sizeof(int); break;
|
||||||
|
case RTLSDR_TUNER_FC0013: table = fc0013; count = sizeof(fc0013) / sizeof(int); break;
|
||||||
|
case RTLSDR_TUNER_R820T:
|
||||||
|
case RTLSDR_TUNER_R828D: table = r82xx; count = sizeof(r82xx) / sizeof(int); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gains != NULL) {
|
||||||
|
memcpy(gains, table, count * sizeof(int));
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//close the rtl_tcp connection; returns close's result
|
||||||
|
static int rtltcp_close(void)
|
||||||
|
{
|
||||||
|
int r = close(rtltcp_sock);
|
||||||
|
rtltcp_sock = -1;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pass rtl_tcp samples to cb until the connection closes or exitflag is set, in the same block size that rtlsdr_read_async delivers by default
|
||||||
|
static int rtltcp_read_async(rtlsdr_read_async_cb_t cb, void *ctx)
|
||||||
|
{
|
||||||
|
static unsigned char buf[RTLTCP_BUF_LENGTH];
|
||||||
|
size_t received = 0;
|
||||||
|
|
||||||
|
//receive until exit is requested or the connection ends; no deadline, so an idle stream can wait indefinitely
|
||||||
|
while (rtltcp_wait(rtltcp_sock, POLLIN, -1) == 0) {
|
||||||
|
ssize_t n = recv(rtltcp_sock, buf + received, sizeof(buf) - received, 0);
|
||||||
|
if (n < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) continue;
|
||||||
|
if (n <= 0) break;
|
||||||
|
received += n;
|
||||||
|
if (received == sizeof(buf)) {
|
||||||
|
cb(buf, sizeof(buf), ctx);
|
||||||
|
received = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//we are finished (for a variety of reasons). ensure exitflag is set
|
||||||
|
if (!exitflag) {
|
||||||
|
fprintf (stderr, "rtl_tcp server closed the connection.\n");
|
||||||
|
exitflag = 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Each rtlsdr_or_tcp_* function takes the arguments of the librtlsdr function it is named after.
|
||||||
|
//While an rtl_tcp server is connected, the call goes to the server; otherwise it goes to librtlsdr.
|
||||||
|
int rtlsdr_or_tcp_close(rtlsdr_dev_t *dev)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_close() : rtlsdr_close(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx, uint32_t buf_num, uint32_t buf_len)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_read_async(cb, ctx) : rtlsdr_read_async(dev, cb, ctx, buf_num, buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_cancel_async(rtlsdr_dev_t *dev)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? shutdown(rtltcp_sock, SHUT_RDWR) : rtlsdr_cancel_async(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_reset_buffer(rtlsdr_dev_t *dev)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? 0 : rtlsdr_reset_buffer(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_get_tuner_gains(gains) : rtlsdr_get_tuner_gains(dev, gains);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_CENTER_FREQ, freq) : rtlsdr_set_center_freq(dev, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_SAMPLE_RATE, rate) : rtlsdr_set_sample_rate(dev, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_direct_sampling(rtlsdr_dev_t *dev, int on)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_DIRECT_SAMPLING, on) : rtlsdr_set_direct_sampling(dev, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_offset_tuning(rtlsdr_dev_t *dev, int on)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_OFFSET_TUNING, on) : rtlsdr_set_offset_tuning(dev, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_TUNER_GAIN_MODE, manual) : rtlsdr_set_tuner_gain_mode(dev, manual);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain(rtlsdr_dev_t *dev, int gain)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_TUNER_GAIN, gain) : rtlsdr_set_tuner_gain(dev, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_freq_correction(rtlsdr_dev_t *dev, int ppm)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_FREQ_CORRECTION, ppm) : rtlsdr_set_freq_correction(dev, ppm);
|
||||||
|
}
|
||||||
@@ -595,7 +595,7 @@ void pn95_lfsr() //test to see if this generates the correct bits now
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start, int stop )
|
void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t * dbuf, int start, int stop )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
@@ -850,7 +850,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send VCH to ehr voice handler
|
// send VCH to ehr voice handler
|
||||||
ysf_ehr (opts, state, vbuf, 0, 4);
|
ysf_ehr (opts, state, vbuf, 0, 5);
|
||||||
|
|
||||||
//send DCH to decoder
|
//send DCH to decoder
|
||||||
ysf_conv_dch (opts, state, bn, bt, fn, ft, cm, dbuf);
|
ysf_conv_dch (opts, state, bn, bt, fn, ft, cm, dbuf);
|
||||||
|
|||||||
Reference in New Issue
Block a user