merge branch max into master

master
Max 3 years ago
commit b6b0eeb7b8
  1. 3
      CMakeLists.txt
  2. 2
      install.sh
  3. 7
      op25/gr-op25/CMakeLists.txt
  4. 12
      op25/gr-op25/grc/op25_decoder_ff.xml
  5. 13
      op25/gr-op25/grc/op25_fsk4_demod_ff.xml
  6. 13
      op25/gr-op25/include/op25/decoder_bf.h
  7. 7
      op25/gr-op25/lib/CMakeLists.txt
  8. 21
      op25/gr-op25/lib/abstract_data_unit.cc
  9. 24
      op25/gr-op25/lib/abstract_data_unit.h
  10. 162
      op25/gr-op25/lib/bch.cc
  11. 4
      op25/gr-op25/lib/bch.h
  12. 286
      op25/gr-op25/lib/crypto.cc
  13. 73
      op25/gr-op25/lib/crypto.h
  14. 64
      op25/gr-op25/lib/crypto_module_du_handler.cc
  15. 21
      op25/gr-op25/lib/crypto_module_du_handler.h
  16. 6
      op25/gr-op25/lib/data_unit.h
  17. 110
      op25/gr-op25/lib/decoder_bf_impl.cc
  18. 26
      op25/gr-op25/lib/decoder_bf_impl.h
  19. 8
      op25/gr-op25/lib/decoder_ff_impl.cc
  20. 15
      op25/gr-op25/lib/des.h
  21. 124
      op25/gr-op25/lib/deskey.c
  22. 236
      op25/gr-op25/lib/desport.c
  23. 131
      op25/gr-op25/lib/dessp.c
  24. 75
      op25/gr-op25/lib/hdu.cc
  25. 15
      op25/gr-op25/lib/hdu.h
  26. 102
      op25/gr-op25/lib/ldu.cc
  27. 28
      op25/gr-op25/lib/ldu.h
  28. 69
      op25/gr-op25/lib/ldu1.cc
  29. 40
      op25/gr-op25/lib/ldu1.h
  30. 50
      op25/gr-op25/lib/ldu2.cc
  31. 17
      op25/gr-op25/lib/ldu2.h
  32. 113
      op25/gr-op25/lib/op25.i
  33. 15
      op25/gr-op25/lib/op25_hamming.h
  34. 74
      op25/gr-op25/lib/op25_imbe_frame.h
  35. 37
      op25/gr-op25/lib/value_string.cc
  36. 301
      op25/gr-op25/lib/voice_data_unit.cc
  37. 17
      op25/gr-op25/lib/voice_data_unit.h
  38. 7
      op25/gr-op25/lib/voice_du_handler.cc
  39. 5
      op25/gr-op25/lib/voice_du_handler.h
  40. 7
      op25/gr-op25/swig/op25_swig.i
  41. 8
      op25/gr-op25_repeater/CMakeLists.txt
  42. 79
      op25/gr-op25_repeater/apps/README
  43. 53
      op25/gr-op25_repeater/apps/audio.py
  44. 49
      op25/gr-op25_repeater/apps/cfg.json
  45. 221
      op25/gr-op25_repeater/apps/gr_gnuplot.py
  46. 446
      op25/gr-op25_repeater/apps/http.py
  47. 260
      op25/gr-op25_repeater/apps/multi_rx.py
  48. 14
      op25/gr-op25_repeater/apps/p25_decoder.py
  49. 191
      op25/gr-op25_repeater/apps/p25_demodulator.py
  50. 437
      op25/gr-op25_repeater/apps/rx.py
  51. 153
      op25/gr-op25_repeater/apps/sockaudio.py
  52. 347
      op25/gr-op25_repeater/apps/terminal.py
  53. 468
      op25/gr-op25_repeater/apps/trunking.py
  54. 128
      op25/gr-op25_repeater/apps/tsvfile.py
  55. 41
      op25/gr-op25_repeater/apps/tx/dstar-cfg.dat
  56. 61
      op25/gr-op25_repeater/apps/tx/dv_tx.py
  57. 37
      op25/gr-op25_repeater/apps/tx/multi_tx.py
  58. 57
      op25/gr-op25_repeater/apps/tx/op25_c4fm_mod.py
  59. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/1011.pattern
  60. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/afc1011.pattern
  61. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/bercalhex.pattern
  62. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/busyhex.pattern
  63. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/idlehex.pattern
  64. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/silencehex.pattern
  65. 24
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/1011hex.dat
  66. 24
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/afc1011hex.dat
  67. 24
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/bercalhex.dat
  68. 24
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/busyhex.dat
  69. 24
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/idlehex.dat
  70. 25
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/make-bin.py
  71. 24
      op25/gr-op25_repeater/apps/tx/testpatterns/sources/silencehex.dat
  72. BIN
      op25/gr-op25_repeater/apps/tx/testpatterns/test.wav
  73. 2
      op25/gr-op25_repeater/apps/tx/ysf-cfg.dat
  74. 3
      op25/gr-op25_repeater/include/op25_repeater/CMakeLists.txt
  75. 60
      op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h
  76. 2
      op25/gr-op25_repeater/include/op25_repeater/gardner_costas_cc.h
  77. 1
      op25/gr-op25_repeater/include/op25_repeater/p25_frame_assembler.h
  78. 93
      op25/gr-op25_repeater/lib/CCITTChecksumReverse.cpp
  79. 39
      op25/gr-op25_repeater/lib/CCITTChecksumReverse.h
  80. 23
      op25/gr-op25_repeater/lib/CMakeLists.txt
  81. 2
      op25/gr-op25_repeater/lib/ambe.c
  82. 3
      op25/gr-op25_repeater/lib/ambe_encoder.cc
  83. 4
      op25/gr-op25_repeater/lib/ambe_encoder.h
  84. 59
      op25/gr-op25_repeater/lib/bit_utils.h
  85. 2
      op25/gr-op25_repeater/lib/check_frame_sync.h
  86. 35
      op25/gr-op25_repeater/lib/crc16.h
  87. 362
      op25/gr-op25_repeater/lib/d2460.cc
  88. 2
      op25/gr-op25_repeater/lib/dmr_bs_tx_bb_impl.cc
  89. 18
      op25/gr-op25_repeater/lib/dmr_const.h
  90. 130
      op25/gr-op25_repeater/lib/dstar_header.h
  91. 42
      op25/gr-op25_repeater/lib/dstar_tx_sb_impl.cc
  92. 1
      op25/gr-op25_repeater/lib/dstar_tx_sb_impl.h
  93. 128
      op25/gr-op25_repeater/lib/ezpwd/asserter
  94. 485
      op25/gr-op25_repeater/lib/ezpwd/bch
  95. 219
      op25/gr-op25_repeater/lib/ezpwd/bch_base
  96. 506
      op25/gr-op25_repeater/lib/ezpwd/corrector
  97. 9
      op25/gr-op25_repeater/lib/ezpwd/definitions
  98. 725
      op25/gr-op25_repeater/lib/ezpwd/ezcod
  99. 344
      op25/gr-op25_repeater/lib/ezpwd/output
  100. 168
      op25/gr-op25_repeater/lib/ezpwd/rs
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 2.6)
project(gr-op25 CXX C)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "-std=c++11")
add_subdirectory(op25/gr-op25)
add_subdirectory(op25/gr-op25_repeater)

@ -12,7 +12,7 @@ fi
sudo apt-get update
sudo apt-get build-dep gnuradio
sudo apt-get install gnuradio gnuradio-dev gr-osmosdr librtlsdr-dev libuhd-dev libhackrf-dev libitpp-dev libpcap-dev cmake git swig build-essential pkg-config doxygen
sudo apt-get install gnuradio gnuradio-dev gr-osmosdr librtlsdr-dev libuhd-dev libhackrf-dev libitpp-dev libpcap-dev cmake git swig build-essential pkg-config doxygen python-numpy python-waitress python-requests
mkdir build
cd build

@ -83,7 +83,6 @@ set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
########################################################################
# Find gnuradio build dependencies
########################################################################
find_package(GnuradioRuntime)
find_package(CppUnit)
# To run a more advanced search for GNU Radio and it's components and
@ -93,10 +92,8 @@ find_package(CppUnit)
#
# set(GR_REQUIRED_COMPONENTS RUNTIME BLOCKS FILTER ...)
# find_package(Gnuradio "version")
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(GR_REQUIRED_COMPONENTS RUNTIME BLOCKS FILTER PMT)
find_package(Gnuradio)
endif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(GR_REQUIRED_COMPONENTS RUNTIME BLOCKS FILTER PMT)
find_package(Gnuradio)
if(NOT GNURADIO_RUNTIME_FOUND)
message(FATAL_ERROR "GnuRadio Runtime required to compile op25")

@ -4,17 +4,17 @@
<key>op25_decoder_ff</key>
<category>op25</category>
<import>import op25</import>
<make>op25.decoder_ff($)</make>
<make>op25.decoder_ff()</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
<param>
<!--<param>
<name>...</name>
<key>...</key>
<type>...</type>
</param>
</param>-->
<!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI)
@ -23,7 +23,7 @@
* optional (set to 1 for optional inputs) -->
<sink>
<name>in</name>
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
<type>float</type>
</sink>
<!-- Make one 'source' node per output. Sub-nodes:
@ -32,7 +32,7 @@
* vlen
* optional (set to 1 for optional inputs) -->
<source>
<name>out</name>
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
<name>audio</name>
<type>float</type>
</source>
</block>

@ -4,7 +4,7 @@
<key>op25_fsk4_demod_ff</key>
<category>op25</category>
<import>import op25</import>
<make>op25.fsk4_demod_ff(self.auto_tune_msgq, $sample_rate, $symbol_rate)</make>
<make>op25.fsk4_demod_ff($(id)_msgq_out, $sample_rate, $symbol_rate)</make>
<param>
<name>Sample Rate</name>
@ -20,7 +20,8 @@
<type>real</type>
</param>
<param>
<!-- Must connect tune message queue as the block expects a queue as first argument! -->
<!--<param>
<name>Output Auto Tune</name>
<key>tune_out</key>
<value>True</value>
@ -34,7 +35,7 @@
<name>No</name>
<key>False</key>
</option>
</param>
</param>-->
<sink>
<name>in</name>
@ -45,4 +46,10 @@
<name>dibits</name>
<type>float</type>
</source>
<source>
<name>tune</name>
<type>msg</type>
<!--<optional>1</optional>-->
</source>
</block>

@ -51,7 +51,7 @@ namespace gr {
* class. op25::decoder_bf::make is the public interface for
* creating new instances.
*/
static sptr make();
static sptr make(bool idle_silence = true, bool verbose = false);
/**
* Return a pointer to a string identifying the destination of
@ -78,6 +78,17 @@ namespace gr {
* message queue.
*/
virtual void set_msgq(gr::msg_queue::sptr msgq) = 0;
virtual void set_idle_silence(bool idle_silence = true) = 0;
virtual void set_logging(bool verbose = true) = 0;
typedef std::vector<uint8_t> key_type;
typedef std::map<uint16_t, key_type> key_map_type;
virtual void set_key(const key_type& key) = 0;
virtual void set_key_map(const key_map_type& keys) = 0;
};
} // namespace op25

@ -53,6 +53,13 @@ list(APPEND op25_sources
value_string.cc
pickle.cc
pcap_source_b_impl.cc
bch.cc
ldu.cc
crypto.cc
crypto_module_du_handler.cc
deskey.c
desport.c
dessp.c
)
add_library(gnuradio-op25 SHARED ${op25_sources})

@ -55,10 +55,10 @@ abstract_data_unit::correct_errors()
}
void
abstract_data_unit::decode_audio(imbe_decoder& imbe)
abstract_data_unit::decode_audio(imbe_decoder& imbe, crypto_module::sptr crypto_mod)
{
if(is_complete()) {
do_decode_audio(d_frame_body, imbe);
do_decode_audio(d_frame_body, imbe, crypto_mod);
} else {
ostringstream msg;
msg << "cannot decode audio - frame is not complete" << endl;
@ -153,7 +153,8 @@ abstract_data_unit::dump(ostream& os) const
}
abstract_data_unit::abstract_data_unit(const_bit_queue& frame_body) :
d_frame_body(frame_body.size())
d_frame_body(frame_body.size()),
d_logging_enabled(false)
{
copy(frame_body.begin(), frame_body.end(), d_frame_body.begin());
}
@ -164,7 +165,7 @@ abstract_data_unit::do_correct_errors(bit_vector& frame_body)
}
void
abstract_data_unit::do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe)
abstract_data_unit::do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe, crypto_module::sptr crypto_mod)
{
}
@ -179,3 +180,15 @@ abstract_data_unit::frame_size() const
{
return d_frame_body.size();
}
void
abstract_data_unit::set_logging(bool on)
{
d_logging_enabled = on;
}
bool
abstract_data_unit::logging_enabled() const
{
return d_logging_enabled;
}

@ -26,6 +26,7 @@
#include "data_unit.h"
#include "op25_yank.h"
#include "crypto.h"
#include <string>
#include <vector>
@ -62,7 +63,7 @@ public:
* \precondition is_complete() == true.
* \param imbe The imbe_decoder to use to generate the audio.
*/
virtual void decode_audio(imbe_decoder& imbe);
virtual void decode_audio(imbe_decoder& imbe, crypto_module::sptr crypto_mod);
/**
* Decode the frame into an octet vector.
@ -117,6 +118,15 @@ public:
*/
virtual std::string snapshot() const;
/**
* Returns a string describing the Data Unit ID (DUID).
*
* \return A string identifying the DUID.
*/
virtual std::string duid_str() const = 0;
virtual void set_logging(bool on);
protected:
/**
@ -140,7 +150,7 @@ protected:
* \param frame_body The const_bit_vector to decode.
* \param imbe The imbe_decoder to use.
*/
virtual void do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe);
virtual void do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe, crypto_module::sptr crypto_mod);
/**
* Decode frame_body and write the decoded frame contents to msg.
@ -152,13 +162,6 @@ protected:
*/
virtual size_t decode_frame(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg);
/**
* Returns a string describing the Data Unit ID (DUID).
*
* \return A string identifying the DUID.
*/
virtual std::string duid_str() const = 0;
/**
* Return a reference to the frame body.
*/
@ -180,6 +183,8 @@ protected:
*/
virtual uint16_t frame_size() const;
virtual bool logging_enabled() const;
private:
/**
@ -187,6 +192,7 @@ private:
*/
bit_vector d_frame_body;
bool d_logging_enabled;
};
#endif /* INCLUDED_ABSTRACT_DATA_UNIT_H */

@ -0,0 +1,162 @@
#include <stdio.h>
#include <vector>
#include "bch.h"
/*
* Copyright 2010, KA1RBI
*/
static const int bchGFexp[64] = {
1, 2, 4, 8, 16, 32, 3, 6, 12, 24, 48, 35, 5, 10, 20, 40,
19, 38, 15, 30, 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, 51, 37,
9, 18, 36, 11, 22, 44, 27, 54, 47, 29, 58, 55, 45, 25, 50, 39,
13, 26, 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, 57, 49, 33, 0
};
static const int bchGFlog[64] = {
-1, 0, 1, 6, 2, 12, 7, 26, 3, 32, 13, 35, 8, 48, 27, 18,
4, 24, 33, 16, 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, 19, 56,
5, 62, 25, 11, 34, 31, 17, 47, 15, 23, 53, 51, 37, 44, 55, 40,
10, 61, 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, 20, 59, 57, 58
};
static const int bchG[48] = {
1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0,
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0,
1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1
};
int bchDec(bit_vector& Codeword)
{
int elp[24][ 22], S[23];
int D[23], L[24], uLu[24];
int root[11], locn[11], reg[12];
int i,j,U,q,count;
int SynError, CantDecode;
SynError = 0; CantDecode = 0;
for(i = 1; i <= 22; i++) {
S[i] = 0;
// FOR j = 0 TO 62
for(j = 0; j <= 62; j++) {
if( Codeword[j]) { S[i] = S[i] ^ bchGFexp[(i * j) % 63]; }
}
if( S[i]) { SynError = 1; }
S[i] = bchGFlog[S[i]];
// printf("S[%d] %d\n", i, S[i]);
}
if( SynError) { //if there are errors, try to correct them
L[0] = 0; uLu[0] = -1; D[0] = 0; elp[0][ 0] = 0;
L[1] = 0; uLu[1] = 0; D[1] = S[1]; elp[1][ 0] = 1;
//FOR i = 1 TO 21
for(i = 1; i <= 21; i++) {
elp[0][ i] = -1; elp[1][ i] = 0;
}
U = 0;
do {
U = U + 1;
if( D[U] == -1) {
L[U + 1] = L[U];
// FOR i = 0 TO L[U]
for(i = 0; i <= L[U]; i++) {
elp[U + 1][ i] = elp[U][ i]; elp[U][ i] = bchGFlog[elp[U][ i]];
}
} else {
//search for words with greatest uLu(q) for which d(q)!=0
q = U - 1;
while((D[q] == -1) &&(q > 0)) { q = q - 1; }
//have found first non-zero d(q)
if( q > 0) {
j = q;
do { j = j - 1; if((D[j] != -1) &&(uLu[q] < uLu[j])) { q = j; }
} while( j > 0) ;
}
//store degree of new elp polynomial
if( L[U] > L[q] + U - q) {
L[U + 1] = L[U] ;
} else {
L[U + 1] = L[q] + U - q;
}
///* form new elp(x) */
// FOR i = 0 TO 21
for(i = 0; i <= 21; i++) {
elp[U + 1][ i] = 0;
}
// FOR i = 0 TO L(q)
for(i = 0; i <= L[q]; i++) {
if( elp[q][ i] != -1) {
elp[U + 1][ i + U - q] = bchGFexp[(D[U] + 63 - D[q] + elp[q][ i]) % 63];
}
}
// FOR i = 0 TO L(U)
for(i = 0; i <= L[U]; i++) {
elp[U + 1][ i] = elp[U + 1][ i] ^ elp[U][ i];
elp[U][ i] = bchGFlog[elp[U][ i]];
}
}
uLu[U + 1] = U - L[U + 1];
//form(u+1)th discrepancy
if( U < 22) {
//no discrepancy computed on last iteration
if( S[U + 1] != -1) { D[U + 1] = bchGFexp[S[U + 1]]; } else { D[U + 1] = 0; }
// FOR i = 1 TO L(U + 1)
for(i = 1; i <= L[U + 1]; i++) {
if((S[U + 1 - i] != -1) &&(elp[U + 1][ i] != 0)) {
D[U + 1] = D[U + 1] ^ bchGFexp[(S[U + 1 - i] + bchGFlog[elp[U + 1][ i]]) % 63];
}
}
//put d(u+1) into index form */
D[U + 1] = bchGFlog[D[U + 1]];
}
} while((U < 22) &&(L[U + 1] <= 11));
U = U + 1;
if( L[U] <= 11) { // /* Can correct errors */
//put elp into index form
// FOR i = 0 TO L[U]
for(i = 0; i <= L[U]; i++) {
elp[U][ i] = bchGFlog[elp[U][ i]];
}
//Chien search: find roots of the error location polynomial
// FOR i = 1 TO L(U)
for(i = 1; i <= L[U]; i++) {
reg[i] = elp[U][ i];
}
count = 0;
// FOR i = 1 TO 63
for(i = 1; i <= 63; i++) {
q = 1;
//FOR j = 1 TO L(U)
for(j = 1; j <= L[U]; j++) {
if( reg[j] != -1) {
reg[j] =(reg[j] + j) % 63; q = q ^ bchGFexp[reg[j]];
}
}
if( q == 0) { //store root and error location number indices
root[count] = i; locn[count] = 63 - i; count = count + 1;
}
}
if( count == L[U]) {
//no. roots = degree of elp hence <= t errors
//FOR i = 0 TO L[U] - 1
for(i = 0; i <= L[U]-1; i++) {
Codeword[locn[i]] = Codeword[locn[i]] ^ 1;
}
CantDecode = count;
} else { //elp has degree >t hence cannot solve
CantDecode = -1;
}
} else {
CantDecode = -2;
}
}
return CantDecode;
}

@ -0,0 +1,4 @@
#include <vector>
typedef std::vector<bool> bit_vector;
int bchDec(bit_vector& Codeword);

@ -0,0 +1,286 @@
#include "crypto.h"
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
#include <stdio.h>
#include <memory.h>
extern "C" {
#include "des.h"
}
static unsigned long long swap_bytes(uint64_t l)
{
unsigned long long r;
unsigned char* pL = (unsigned char*)&l;
unsigned char* pR = (unsigned char*)&r;
for (int i = 0; i < sizeof(l); ++i)
pR[i] = pL[(sizeof(l) - 1) - i];
return r;
}
///////////////////////////////////////////////////////////////////////////////
/*
class null_algorithm : public crypto_algorithm // This is an algorithm skeleton (can be used for no encryption as pass-through)
{
private:
size_t m_generated_bits;
public:
null_algorithm()
: m_generated_bits(0)
{
}
const type_id id() const
{
return crypto_algorithm::NONE;
}
bool update(const struct CryptoState& state)
{
fprintf(stderr, "NULL:\t%d bits generated\n", m_generated_bits);
m_generated_bits = 0;
return true;
}
bool set_key(const crypto_algorithm::key_type& key)
{
return true;
}
uint64_t generate(size_t n)
{
m_generated_bits += n;
return 0;
}
};
*/
///////////////////////////////////////////////////////////////////////////////
class des_ofb : public crypto_algorithm
{
public:
unsigned long long m_key_des, m_next_iv, m_ks;
int m_ks_idx;
DES_KS m_ksDES;
int m_iterations;
uint16_t m_current_kid;
key_type m_default_key;
key_map_type m_key_map;
bool m_verbose;
public:
des_ofb()
: m_current_kid(-1)
{
memset(&m_ksDES, 0, sizeof(m_ksDES));
m_key_des = 0;
m_next_iv = 0;
m_ks_idx = 0;
m_ks = 0;
m_iterations = 0;
}
void set_logging(bool on)
{
m_verbose = on;
}
const type_id id() const
{
return crypto_algorithm::DES_OFB;
}
bool update(const struct CryptoState& state)
{
if (m_current_kid != state.kid)
{
if (m_key_map.empty())
{
// Nothing to do
}
else
{
key_map_type::iterator it = m_key_map.find(state.kid);
if (it != m_key_map.end())
{
set_key(it->second);
}
else if (!m_default_key.empty())
{
/*if (m_verbose) */fprintf(stderr, "Key 0x%04x not found in key map - using default key\n", state.kid);
set_key(m_default_key);
}
else
{
/*if (m_verbose) */fprintf(stderr, "Key 0x%04x not found in key map and no default key\n", state.kid);
}
}
m_current_kid = state.kid;
}
uint64_t iv = 0;
size_t n = std::min(sizeof(iv), state.mi.size());
memcpy(&iv, &state.mi[0], n);
set_iv(iv);
return (n == 8);
}
void set_key_map(const key_map_type& key_map)
{
m_key_map = key_map;
m_current_kid = -1; // To refresh on next update if it has changed
}
bool set_key(const crypto_algorithm::key_type& key)
{
const size_t valid_key_length = 8;
if (key.size() != valid_key_length)
{
if (m_verbose) fprintf(stderr, "DES:\tIncorrect key length of %lu (should be %lu)\n", key.size(), valid_key_length);
return false;
}
m_default_key = key;
memcpy(&m_key_des, &key[0], std::min(key.size(), sizeof(m_key_des)));
if (m_verbose)
{
std::stringstream ss;
for (int i = 0; i < valid_key_length; ++i)
ss << boost::format("%02X") % (int)key[i];
std::cerr << "DES:\tKey: " << ss.str() << std::endl;
}
deskey(m_ksDES, (unsigned char*)&m_key_des, 0); // 0: encrypt (for OFB mode)
return true;
}
void set_iv(uint64_t iv)
{
if (m_iterations > 0)
{
if (m_verbose) fprintf(stderr, "DES:\t%i bits used from %i iterations\n", m_ks_idx, m_iterations);
}
m_next_iv = iv;
m_ks_idx = 0;
m_iterations = 0;
m_ks = m_next_iv;
des(m_ksDES, (unsigned char*)&m_ks); // First initialisation
++m_iterations;
des(m_ksDES, (unsigned char*)&m_ks); // Throw out first iteration & prepare for second
++m_iterations;
generate(64); // Reserved 3 + first 5 of LC (3 left)
generate(3 * 8); // Use remaining 3 bytes for LC
}
uint64_t generate(size_t count) // 1..64
{
unsigned long long ullCurrent = swap_bytes(m_ks);
const int max_len = 64;
int pos = m_ks_idx % max_len;
m_ks_idx += count;
if ((pos + count) <= max_len) // Up to 64
{
if ((m_ks_idx % max_len) == 0)
{
des(m_ksDES, (unsigned char*)&m_ks); // Prepare for next iteration
++m_iterations;
}
unsigned long long result = (ullCurrent >> (((max_len - 1) - pos) - (count-1))) & ((count == max_len) ? (unsigned long long)-1 : ((1ULL << count) - 1));
return result;
}
// Over-flow 64-bit boundary (so all of rest of current will be used)
des(m_ksDES, (unsigned char*)&m_ks); // Compute second part
++m_iterations;
unsigned long long first = ullCurrent << pos; // RHS will be zeros
ullCurrent = swap_bytes(m_ks);
int remainder = count - (max_len - pos);
first >>= (((max_len - 1) - remainder) - ((max_len - 1) - pos));
unsigned long long next = (ullCurrent >> (((max_len - 1) - 0) - (remainder-1))) & ((1ULL << remainder) - 1);
return (first | next);
}
};
///////////////////////////////////////////////////////////////////////////////
crypto_module::crypto_module(bool verbose/* = true*/)
: d_verbose(verbose)
{
}
crypto_algorithm::sptr crypto_module::algorithm(crypto_algorithm::type_id algid)
{
if ((!d_current_algorithm && (algid == crypto_algorithm::NONE)) || // This line should be commented out if 'null_algorithm' is to be tested
(d_current_algorithm && (algid == d_current_algorithm->id())))
return d_current_algorithm;
switch (algid)
{
case crypto_algorithm::DES_OFB:
d_current_algorithm = crypto_algorithm::sptr(new des_ofb());
break;
//case crypto_algorithm::NONE:
// d_current_algorithm = crypto_algorithm::sptr(new null_algorithm());
// break;
default:
d_current_algorithm = crypto_algorithm::sptr();
};
if (d_current_algorithm)
{
d_current_algorithm->set_logging(logging_enabled());
if (!d_persistent_key_map.empty())
d_current_algorithm->set_key_map(d_persistent_key_map);
if (!d_persistent_key.empty())
d_current_algorithm->set_key(d_persistent_key);
}
return d_current_algorithm;
}
void crypto_module::set_key(const crypto_algorithm::key_type& key)
{
d_persistent_key = key;
if (d_current_algorithm)
d_current_algorithm->set_key(d_persistent_key);
}
void crypto_module::set_key_map(const crypto_algorithm::key_map_type& keys)
{
d_persistent_key_map = keys;
if (d_current_algorithm)
d_current_algorithm->set_key_map(d_persistent_key_map);
}
void crypto_module::set_logging(bool on/* = true*/)
{
d_verbose = on;
if (d_current_algorithm)
d_current_algorithm->set_logging(on);
}

@ -0,0 +1,73 @@
#ifndef INCLUDED_CRYPTO_H
#define INCLUDED_CRYPTO_H
#include <stdint.h>
#include <vector>
#include <map>
#include <boost/shared_ptr.hpp>
static const int MESSAGE_INDICATOR_LENGTH = 9;
class CryptoState
{
public:
CryptoState() :
kid(0), algid(0), mi(MESSAGE_INDICATOR_LENGTH)
{ }
public:
std::vector<uint8_t> mi;
uint16_t kid;
uint8_t algid;
};
class crypto_state_provider
{
public:
virtual struct CryptoState crypto_state() const=0;
};
class crypto_algorithm
{
public:
typedef boost::shared_ptr<class crypto_algorithm> sptr;
typedef std::vector<uint8_t> key_type;
typedef std::map<uint16_t, key_type > key_map_type;
typedef uint8_t type_id;
enum
{
NONE = 0x80,
DES_OFB = 0x81,
};
public:
virtual const type_id id() const=0;
virtual bool set_key(const key_type& key)=0;
virtual void set_key_map(const key_map_type& key_map)=0;
virtual bool update(const struct CryptoState& state)=0;
virtual uint64_t generate(size_t n_bits)=0; // Can request up to 64 bits of key stream at one time
virtual void set_logging(bool on)=0;
};
class crypto_module
{
public:
typedef boost::shared_ptr<class crypto_module> sptr;
public:
crypto_module(bool verbose = false);
public:
virtual crypto_algorithm::sptr algorithm(crypto_algorithm::type_id algid);
virtual void set_key(const crypto_algorithm::key_type& key);
virtual void set_key_map(const crypto_algorithm::key_map_type& keys);
virtual void set_logging(bool on = true);
protected:
crypto_algorithm::sptr d_current_algorithm;
crypto_algorithm::key_type d_persistent_key;
crypto_algorithm::key_map_type d_persistent_key_map;
bool d_verbose;
public:
virtual crypto_algorithm::sptr current_algorithm() const
{ return d_current_algorithm; }
virtual bool logging_enabled() const
{ return d_verbose; }
};
#endif // INCLUDED_CRYPTO_H

@ -0,0 +1,64 @@
#include "crypto_module_du_handler.h"
#include "abstract_data_unit.h"
#include <boost/format.hpp>
#include <sstream>
#include <stdio.h>
crypto_module_du_handler::crypto_module_du_handler(data_unit_handler_sptr next, crypto_module::sptr crypto_mod)
: data_unit_handler(next)
, d_crypto_mod(crypto_mod)
{
}
void
crypto_module_du_handler::handle(data_unit_sptr du)
{
if (!d_crypto_mod)
{
data_unit_handler::handle(du);
return;
}
crypto_state_provider* p = dynamic_cast<crypto_state_provider*>(du.get());
if (p == NULL)
{
data_unit_handler::handle(du);
return;
}
CryptoState state = p->crypto_state();
///////////////////////////////////
if (d_crypto_mod->logging_enabled())
{
std::string duid_str("?");
abstract_data_unit* adu = dynamic_cast<abstract_data_unit*>(du.get());
if (adu)
duid_str = adu->duid_str();
std::stringstream ss;
for (size_t n = 0; n < state.mi.size(); ++n)
ss << (boost::format("%02x") % (int)state.mi[n]);
fprintf(stderr, "%s:\tAlgID: 0x%02x, KID: 0x%04x, MI: %s\n", duid_str.c_str(), state.algid, state.kid, ss.str().c_str());
}
///////////////////////////////////
crypto_algorithm::sptr algorithm = d_crypto_mod->algorithm(state.algid);
if (!algorithm)
{
data_unit_handler::handle(du);
return;
}
// TODO: Could do key management & selection here with 'state.kid'
// Assuming we're only using one key (ignoring 'kid')
algorithm->update(state);
data_unit_handler::handle(du);
}

@ -0,0 +1,21 @@
#ifndef INCLUDED_CRYPTO_MODULE_DU_HANDLER_H
#define INCLUDED_CRYPTO_MODULE_DU_HANDLER_H
#include <boost/shared_ptr.hpp>
#include "data_unit_handler.h"
#include "crypto.h"
class crypto_module_du_handler : public data_unit_handler
{
public:
crypto_module_du_handler(data_unit_handler_sptr next, crypto_module::sptr crypto_mod);
public:
typedef boost::shared_ptr<class crypto_module_du_handler> sptr;
public:
virtual void handle(data_unit_sptr du);
private:
crypto_module::sptr d_crypto_mod;
};
#endif //INCLUDED_CRYPTO_MODULE_HANDLER_H

@ -32,6 +32,8 @@
#include <iosfwd>
#include <stdint.h>
#include "crypto.h"
typedef std::deque<bool> bit_queue;
typedef const std::deque<bool> const_bit_queue;
@ -76,7 +78,7 @@ public:
* \precondition is_complete() == true.
* \param imbe The imbe_decoder to use to generate the audio.
*/
virtual void decode_audio(imbe_decoder& imbe) = 0;
virtual void decode_audio(imbe_decoder& imbe, crypto_module::sptr crypto_mod) = 0;
/**
* Decode the frame into an octet vector.
@ -132,6 +134,8 @@ public:
*/
virtual std::string snapshot() const = 0;
virtual void set_logging(bool on) = 0;
protected:
/**

@ -34,6 +34,7 @@
#include "offline_imbe_decoder.h"
#include "voice_du_handler.h"
#include "op25_yank.h"
#include "bch.h"
using namespace std;
@ -41,13 +42,13 @@ namespace gr {
namespace op25 {
decoder_bf::sptr
decoder_bf::make()
decoder_bf::make(bool idle_silence /*= true*/, bool verbose /*= false*/)
{
return gnuradio::get_initial_sptr
(new decoder_bf_impl());
(new decoder_bf_impl(idle_silence, verbose));
}
decoder_bf_impl::decoder_bf_impl() :
decoder_bf_impl::decoder_bf_impl(bool idle_silence /*= true*/, bool verbose /*= false*/) :
gr::block("decoder_bf",
gr::io_signature::make(1, 1, sizeof(uint8_t)),
gr::io_signature::make(0, 1, sizeof(float))),
@ -56,14 +57,25 @@ namespace gr {
d_frame_hdr(),
d_imbe(imbe_decoder::make()),
d_state(SYNCHRONIZING),
d_p25cai_du_handler(NULL)
d_p25cai_du_handler(NULL),
d_idle_silence(idle_silence),
d_verbose(false)
{
set_logging(verbose);
d_p25cai_du_handler = new p25cai_du_handler(d_data_unit_handler,
"224.0.0.1", 23456);
d_data_unit_handler = data_unit_handler_sptr(d_p25cai_du_handler);
d_snapshot_du_handler = new snapshot_du_handler(d_data_unit_handler);
d_data_unit_handler = data_unit_handler_sptr(d_snapshot_du_handler);
d_data_unit_handler = data_unit_handler_sptr(new voice_du_handler(d_data_unit_handler, d_imbe));
d_crypto_module = crypto_module::sptr(new crypto_module(verbose));
d_crypto_module_du_handler = crypto_module_du_handler::sptr(new crypto_module_du_handler(d_data_unit_handler, d_crypto_module));
d_data_unit_handler = data_unit_handler_sptr(d_crypto_module_du_handler);
d_data_unit_handler = data_unit_handler_sptr(new voice_du_handler(d_data_unit_handler, d_imbe, d_crypto_module));
}
decoder_bf_impl::~decoder_bf_impl()
@ -104,34 +116,35 @@ namespace gr {
gr_vector_void_star &output_items)
{
try {
gr::thread::scoped_lock lock(d_mutex);
// process input
const uint8_t *in = reinterpret_cast<const uint8_t*>(input_items[0]);
for(int i = 0; i < ninput_items[0]; ++i) {
dibit d = in[i] & 0x3;
receive_symbol(d);
}
consume_each(ninput_items[0]);
// produce audio
audio_samples *samples = d_imbe->audio();
float *out = reinterpret_cast<float*>(output_items[0]);
const int n = min(static_cast<int>(samples->size()), noutput_items);
if(0 < n) {
copy(samples->begin(), samples->begin() + n, out);
samples->erase(samples->begin(), samples->begin() + n);
}
if(n < noutput_items) {
fill(out + n, out + noutput_items, 0.0);
}
return noutput_items;
// process input
const uint8_t *in = reinterpret_cast<const uint8_t*>(input_items[0]);
for(int i = 0; i < ninput_items[0]; ++i) {
dibit d = in[i] & 0x3;
receive_symbol(d);
}
consume_each(ninput_items[0]);
// produce audio
audio_samples *samples = d_imbe->audio();
float *out = reinterpret_cast<float*>(output_items[0]);
const int n = min(static_cast<int>(samples->size()), noutput_items);
if(0 < n) {
copy(samples->begin(), samples->begin() + n, out);
samples->erase(samples->begin(), samples->begin() + n);
}
if((d_idle_silence) && (n < noutput_items)) {
fill(out + n, out + noutput_items, 0.0);
}
return (d_idle_silence ? noutput_items : n);
} catch(const std::exception& x) {
cerr << x.what() << endl;
exit(1);
cerr << x.what() << endl;
exit(1);
} catch(...) {
cerr << "unhandled exception" << endl;
exit(2); }
cerr << "unhandled exception" << endl;
exit(2); }
}
const char*
@ -177,14 +190,12 @@ namespace gr {
};
size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
itpp::bvec b(63), zeroes(16);
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
bit_vector b(NID_SZ);
yank(d_frame_hdr, NID, NID_SZ, b, 0);
b = bch.decode(b);
if(b != zeroes) {
b = bch.encode(b);
if(bchDec(b) >= 0) {
yank_back(b, 0, d_frame_hdr, NID, NID_SZ);
d_data_unit = data_unit::make_data_unit(d_frame_hdr);
d_data_unit->set_logging(d_verbose);
} else {
data_unit_sptr null;
d_data_unit = null;
@ -229,5 +240,36 @@ namespace gr {
break;
}
}
void
decoder_bf_impl::set_idle_silence(bool idle_silence/* = true*/)
{
gr::thread::scoped_lock lock(d_mutex);
d_idle_silence = idle_silence;
}
void
decoder_bf_impl::set_logging(bool verbose/* = true*/)
{
if (verbose) fprintf(stderr, "[%s<%lu>] verbose logging enabled\n", name().c_str(), unique_id());
d_verbose = verbose;
if (d_crypto_module)
d_crypto_module->set_logging(verbose);
}
void
decoder_bf_impl::set_key(const key_type& key)
{
d_crypto_module->set_key(key);
}
void
decoder_bf_impl::set_key_map(const key_map_type& keys)
{
d_crypto_module->set_key_map(keys);
}
} /* namespace op25 */
} /* namespace gr */

@ -24,11 +24,14 @@
#define INCLUDED_OP25_DECODER_BF_IMPL_H
#include <op25/decoder_bf.h>
#include <gnuradio/thread/thread.h>
#include "data_unit.h"
#include "data_unit_handler.h"
#include "imbe_decoder.h"
#include "p25cai_du_handler.h"
#include "snapshot_du_handler.h"
#include "crypto.h"
#include "crypto_module_du_handler.h"
namespace gr {
namespace op25 {
@ -102,8 +105,21 @@ namespace gr {
*/
class snapshot_du_handler *d_snapshot_du_handler;
/*
* Whether or not to output silence when no audio is synthesised.
*/
bool d_idle_silence;
bool d_verbose;
crypto_module::sptr d_crypto_module;
crypto_module_du_handler::sptr d_crypto_module_du_handler;
gr::thread::mutex d_mutex;
public:
decoder_bf_impl();
decoder_bf_impl(bool idle_silence = true, bool verbose = false);
~decoder_bf_impl();
// Where all the action really happens
@ -139,6 +155,14 @@ namespace gr {
* message queue.
*/
void set_msgq(gr::msg_queue::sptr msgq);
void set_idle_silence(bool idle_silence = true);
void set_logging(bool verbose = true);
void set_key(const key_type& key);
void set_key_map(const key_map_type& keys);
};
} // namespace op25
} // namespace gr

@ -34,6 +34,7 @@
#include "offline_imbe_decoder.h"
#include "voice_du_handler.h"
#include "op25_yank.h"
#include "bch.h"
using namespace std;
@ -185,12 +186,9 @@ namespace gr {
};
size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
itpp::bvec b(63), zeroes(16);
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
bit_vector b(NID_SZ);
yank(d_frame_hdr, NID, NID_SZ, b, 0);
b = bch.decode(b);
if(b != zeroes) {
b = bch.encode(b);
if(bchDec(b) >= 0) {
yank_back(b, 0, d_frame_hdr, NID, NID_SZ);
d_data_unit = data_unit::make_data_unit(d_frame_hdr);
} else {

@ -0,0 +1,15 @@
typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */
typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */
/* In deskey.c: */
void deskey(DES_KS,unsigned char *,int);
void des3key(DES3_KS,unsigned char *,int);
/* In desport.c, desborl.cas or desgnu.s: */
void des(DES_KS,unsigned char *);
/* In des3port.c, des3borl.cas or des3gnu.s: */
void des3(DES3_KS,unsigned char *);
extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */

@ -0,0 +1,124 @@
/* Portable C code to create DES key schedules from user-provided keys
* This doesn't have to be fast unless you're cracking keys or UNIX
* passwords
*/
#include <string.h>
#include "des.h"
/* Key schedule-related tables from FIPS-46 */
/* permuted choice table (key) */
static unsigned char pc1[] = {
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53,