Encrypted OpenBridge, initial commit, add SVRD hooks

This commit is contained in:
KF7EEL 2021-09-04 19:57:15 -07:00
parent 698ae71223
commit 97bb174bf6
8 changed files with 160 additions and 68 deletions

View File

@ -187,7 +187,7 @@ def download_config(L_CONFIG_FILE, cli_file):
for i in iterate_config:
## corrected_config['SYSTEMS'][i]['GROUP_HANGTIME'] = int(iterate_config[i]['GROUP_HANGTIME'])
## corrected_config['SYSTEMS'][i] = {}
print(iterate_config[i])
## print(iterate_config[i])
if iterate_config[i]['MODE'] == 'MASTER' or iterate_config[i]['MODE'] == 'PROXY' or iterate_config[i]['MODE'] == 'OPENBRIDGE':
corrected_config['SYSTEMS'][i]['TG1_ACL'] = config.acl_build(iterate_config[i]['TG1_ACL'], 4294967295)
corrected_config['SYSTEMS'][i]['TG2_ACL'] = config.acl_build(iterate_config[i]['TG2_ACL'], 4294967295)
@ -198,6 +198,8 @@ def download_config(L_CONFIG_FILE, cli_file):
corrected_config['SYSTEMS'][i]['PASSPHRASE'] = (iterate_config[i]['PASSPHRASE'] + b'\x00' * 30)[:20] #bytes(re.sub('', "b'|'", str(iterate_config[i]['PASSPHRASE'])).ljust(20, '\x00')[:20], 'utf-8') #bytes(iterate_config[i]['PASSPHRASE'].ljust(20,'\x00')[:20], 'utf-8')
corrected_config['SYSTEMS'][i]['BOTH_SLOTS'] = iterate_config[i]['BOTH_SLOTS']
corrected_config['SYSTEMS'][i]['TARGET_SOCK'] = (gethostbyname(iterate_config[i]['TARGET_IP']), iterate_config[i]['TARGET_PORT'])
corrected_config['SYSTEMS'][i]['ENCRYPTION_KEY'] = bytes(iterate_config[i]['ENCRYPTION_KEY'], 'utf-8')
corrected_config['SYSTEMS'][i]['USE_ENCRYPTION'] = iterate_config[i]['USE_ENCRYPTION']
if iterate_config[i]['MODE'] == 'PEER' or iterate_config[i]['MODE'] == 'XLXPEER':

View File

@ -300,7 +300,9 @@ def build_config(_config_file):
'USE_ACL': config.getboolean(section, 'USE_ACL'),
'SUB_ACL': config.get(section, 'SUB_ACL'),
'TG1_ACL': config.get(section, 'TGID_ACL'),
'TG2_ACL': 'PERMIT:ALL'
'TG2_ACL': 'PERMIT:ALL',
'USE_ENCRYPTION': config.getboolean(section, 'USE_ENCRYPTION'),
'ENCRYPTION_KEY': bytes(config.get(section, 'ENCRYPTION_KEY'), 'utf-8'),
}})
elif config.get(section, 'MODE') == 'PROXY':
CONFIG['SYSTEMS'].update({section: {
@ -318,7 +320,7 @@ def build_config(_config_file):
'REG_ACL': config.get(section, 'REG_ACL'),
'SUB_ACL': config.get(section, 'SUB_ACL'),
'TG1_ACL': config.get(section, 'TG1_ACL'),
'TG2_ACL': config.get(section, 'TG2_ACL')
'TG2_ACL': config.get(section, 'TG2_ACL'),
}})
CONFIG['SYSTEMS'][section].update({'PEERS': {}})

View File

@ -69,6 +69,10 @@ RPTP = b'RPTP'
RPTA = b'RPTA'
RPTO = b'RPTO'
# Sever Data and Encrypted OBP
SVRD = b'SVRD'
EOBP = b'EOBP'
# Higheset peer ID permitted by HBP
PEER_MAX = 4294967295

View File

@ -108,7 +108,7 @@ STALE_DAYS: 7
# USER MANAGER
# This is where to configure the details for use with a user managment script
[USER_MANAGER]
THIS_SERVER_NAME: My MMDVM Server
THIS_SERVER_NAME: MMDVM_Server
REMOTE_CONFIG_ENABLED: True
# URL of the user managment server
URL: http://localhost:8080/svr
@ -160,6 +160,9 @@ BOTH_SLOTS: True
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL
# Experimental encryption
ENCRYPTION_KEY:
USE_ENCRYPTION: False
# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE MASTERS
# HomeBrew Protocol Master instances go here.

View File

@ -63,6 +63,9 @@ import base64
import libscrc
import re
# Encryption library
from cryptography.fernet import Fernet
# Does anybody read this stuff? There's a PEP somewhere that says I should do this.
__author__ = 'Cortney T. Buffington, N0MJS'
@ -75,6 +78,19 @@ __email__ = 'n0mjs@me.com'
# Global variables used whether we are a module or __main__
systems = {}
# Functions that provide a basic symetrical encryption using Fernet
def encrypt_packet(key, message):
f = Fernet(key)
token = f.encrypt(message)
return token
def decrypt_packet(key, message):
f = Fernet(key)
token = f.decrypt(message, ttl=1)
return token
# Timed loop used for reporting HBP status
def config_reports(_config, _factory):
def reporting_loop(_logger, _server):
@ -148,9 +164,18 @@ class OPENBRIDGE(DatagramProtocol):
_packet = b''.join([_packet[:11], self._config['NETWORK_ID'], _packet[15:]])
#_packet += hmac_new(self._config['PASSPHRASE'],_packet,sha1).digest()
_packet = b''.join([_packet, (hmac_new(self._config['PASSPHRASE'],_packet,sha1).digest())])
if self._config['USE_ENCRYPTION'] == True:
_enc_pkt = encrypt_packet(self._config['ENCRYPTION_KEY'], _packet)
_packet = b'EOBP' + _enc_pkt
self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT']))
# KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!!
# logger.debug('(%s) TX Packet to OpenBridge %s:%s -- %s', self._system, self._config['TARGET_IP'], self._config['TARGET_PORT'], ahex(_packet))
# Special Server Data packet, encrypted using frenet, send
elif _packet[:4] == SVRD:
_enc_pkt = encrypt_packet(self._config['ENCRYPTION_KEY'], _packet)
_packet = b'SVRD' + _enc_pkt
self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT']))
print('Server data')
else:
logger.error('(%s) OpenBridge system was asked to send non DMRD packet: %s', self._system, _packet)
@ -160,9 +185,14 @@ class OPENBRIDGE(DatagramProtocol):
def datagramReceived(self, _packet, _sockaddr):
# Keep This Line Commented Unless HEAVILY Debugging!
#logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_packet))
## logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_packet))
if _packet[:4] == DMRD or _packet[:4] == EOBP:
if _packet[:4] == EOBP:
_d_pkt = decrypt_packet(self._config['ENCRYPTION_KEY'], _packet[4:])
_packet = _d_pkt
if _packet[:4] == DMRD: # DMRData -- encapsulated DMR data frame
# DMRData -- encapsulated DMR data frame
if _packet[:4] == DMRD:
_data = _packet[:53]
_hash = _packet[53:]
_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest()
@ -219,8 +249,11 @@ class OPENBRIDGE(DatagramProtocol):
self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data)
else:
logger.info('(%s) OpenBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s', self._system, _packet[:4], repr(_packet[:53]), len(_packet[53:]), repr(_packet[53:]))
# Server Data packet, decrypt and process it.
elif _packet[:4] == SVRD:
_d_pkt = decrypt_packet(self._config['ENCRYPTION_KEY'], _packet[4:])
print('svr pakcet')
print(_d_pkt)
#************************************************
# HB MASTER CLASS
#************************************************

10
obp_generate_key.py Normal file
View File

@ -0,0 +1,10 @@
# Script to generate a key for Encrypted OpenBridge
from cryptography.fernet import Fernet
import re
def gen_key():
key = Fernet.generate_key()
return key
print('Key: ' + str(gen_key())[2:-1])

View File

@ -9,4 +9,5 @@ maidenhead
requests
libscrc
resettabletimer
cryptography

View File

@ -368,6 +368,8 @@ def create_app():
server = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(500), nullable=False, server_default='')
other_options = db.Column(db.String(1000), nullable=False, server_default='')
encryption_key = db.Column(db.String(200), nullable=False, server_default='')
obp_encryption = db.Column(db.Boolean(), nullable=False, server_default='0')
class BridgeRules(db.Model):
__tablename__ = 'bridge_rules'
@ -2793,7 +2795,9 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
'USE_ACL': obp.use_acl,
'SUB_ACL': obp.sub_acl,
'TG1_ACL': obp.tg_acl,
'TG2_ACL': 'PERMIT:ALL'
'TG2_ACL': 'PERMIT:ALL',
'USE_ENCRYPTION': obp.obp_encryption,
'ENCRYPTION_KEY': obp.encryption_key
}})
for pr in p:
master_config_list.update({pr.name: {
@ -2943,7 +2947,7 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
db.session.delete(m)
db.session.commit()
def edit_master(_mode, _name, _server, _static_positions, _repeat, _active, _max_peers, _ip, _port, _enable_um, _passphrase, _group_hang_time, _use_acl, _reg_acl, _sub_acl, _tg1_acl, _tg2_acl, _enable_unit, _notes, _external_proxy, _int_start_port, _int_stop_port, _network_id, _target_ip, _target_port, _both_slots, _public, _other_options):
def edit_master(_mode, _name, _server, _static_positions, _repeat, _active, _max_peers, _ip, _port, _enable_um, _passphrase, _group_hang_time, _use_acl, _reg_acl, _sub_acl, _tg1_acl, _tg2_acl, _enable_unit, _notes, _external_proxy, _int_start_port, _int_stop_port, _network_id, _target_ip, _target_port, _both_slots, _public, _other_options, _encryption_key, _obp_encryption):
## print(_mode)
#### print(_server)
## print(_name)
@ -2990,6 +2994,8 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
o.enable_unit = _enable_unit
o.notes = _notes
o.other_options = _other_options
o.encryption_key = _encryption_key
o.obp_encryption = _obp_encryption
db.session.commit()
if _mode == 'PROXY':
## print(_int_start_port)
@ -3039,7 +3045,7 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
## )
## db.session.add(add_master)
def add_master(_mode, _name, _server, _static_positions, _repeat, _active, _max_peers, _ip, _port, _enable_um, _passphrase, _group_hang_time, _use_acl, _reg_acl, _sub_acl, _tg1_acl, _tg2_acl, _enable_unit, _notes, _external_proxy, _int_start_port, _int_stop_port, _network_id, _target_ip, _target_port, _both_slots, _public, _other_options):
def add_master(_mode, _name, _server, _static_positions, _repeat, _active, _max_peers, _ip, _port, _enable_um, _passphrase, _group_hang_time, _use_acl, _reg_acl, _sub_acl, _tg1_acl, _tg2_acl, _enable_unit, _notes, _external_proxy, _int_start_port, _int_stop_port, _network_id, _target_ip, _target_port, _both_slots, _public, _other_options, _encryption_key, _obp_encryption):
# print(_mode)
if _mode == 'MASTER':
add_master = MasterList(
@ -3111,7 +3117,9 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
enable_unit = _enable_unit,
server = _server,
notes = _notes,
other_options = _other_options
other_options = _other_options,
encryption_key = _encryption_key,
obp_encryption = _obp_encryption
)
db.session.add(add_OBP)
db.session.commit()
@ -4365,13 +4373,13 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
else:
add_master('PROXY', request.form.get('name_text'), request.form.get('server'), aprs_pos, repeat, active, 0, request.form.get('ip'), request.form.get('external_port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), external_proxy, request.form.get('int_port_start'), request.form.get('int_port_stop'), '', '', '', '', public, request.form.get('other_options'))
add_master('PROXY', request.form.get('name_text'), request.form.get('server'), aprs_pos, repeat, active, 0, request.form.get('ip'), request.form.get('external_port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), external_proxy, request.form.get('int_port_start'), request.form.get('int_port_stop'), '', '', '', '', public, request.form.get('other_options'), '', '')
content = '''<h3 style="text-align: center;">PROXY saved.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
elif request.args.get('proxy_save') == 'edit':
## print(request.args.get('name'))
edit_master('PROXY', request.args.get('name'), request.args.get('server'), aprs_pos, repeat, active, 0, request.form.get('ip'), request.form.get('external_port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), external_proxy, request.form.get('int_port_start'), request.form.get('int_port_stop'), '', '', '', '', public, request.form.get('other_options'))
edit_master('PROXY', request.args.get('name'), request.args.get('server'), aprs_pos, repeat, active, 0, request.form.get('ip'), request.form.get('external_port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), external_proxy, request.form.get('int_port_start'), request.form.get('int_port_stop'), '', '', '', '', public, request.form.get('other_options'), '', '')
content = '''<h3 style="text-align: center;">PROXY changed.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
@ -4386,6 +4394,9 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
use_acl = False
enable_unit = False
both_slots = True
obp_encryption = False
if request.form.get('obp_encryption') == 'True':
obp_encryption = True
if request.form.get('enabled') == 'True':
enabled = True
if request.form.get('use_acl') == 'True':
@ -4400,12 +4411,12 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
else:
add_master('OBP', request.form.get('name_text'), request.form.get('server'), '', '', enabled, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), '', request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('tg_acl'), '', enable_unit, request.form.get('notes'), '', '', '', request.form.get('network_id'), request.form.get('target_ip'), request.form.get('target_port'), both_slots, '', request.form.get('other_options'))
add_master('OBP', request.form.get('name_text'), request.form.get('server'), '', '', enabled, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), '', request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('tg_acl'), '', enable_unit, request.form.get('notes'), '', '', '', request.form.get('network_id'), request.form.get('target_ip'), request.form.get('target_port'), both_slots, '', request.form.get('other_options'), request.form.get('encryption_key'), obp_encryption)
content = '''<h3 style="text-align: center;">OpenBridge connection saved.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
elif request.args.get('OBP_save') == 'edit':
edit_master('OBP', request.args.get('name'), request.args.get('server'), '', '', enabled, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), '', request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('tg_acl'), '', enable_unit, request.form.get('notes'), '', '', '', request.form.get('network_id'), request.form.get('target_ip'), request.form.get('target_port'), both_slots, '', request.form.get('other_options'))
edit_master('OBP', request.args.get('name'), request.args.get('server'), '', '', enabled, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), '', request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('tg_acl'), '', enable_unit, request.form.get('notes'), '', '', '', request.form.get('network_id'), request.form.get('target_ip'), request.form.get('target_port'), both_slots, '', request.form.get('other_options'), request.form.get('encryption_key'), obp_encryption)
content = '''<h3 style="text-align: center;">OpenBridge connection changed.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
@ -4443,12 +4454,12 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
else:
add_master('MASTER', request.form.get('name_text'), request.form.get('server'), aprs_pos, repeat, active, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), '', '', '', '', '', '', '', public, request.form.get('other_options'))
add_master('MASTER', request.form.get('name_text'), request.form.get('server'), aprs_pos, repeat, active, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), '', '', '', '', '', '', '', public, request.form.get('other_options'), '', '')
content = '''<h3 style="text-align: center;">MASTER saved.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" />'''
elif request.args.get('master_save') == 'edit':
edit_master('MASTER', request.args.get('name'), request.args.get('server'), aprs_pos, repeat, active, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), '', '', '', '', '', '', '', public, request.form.get('other_options'))
edit_master('MASTER', request.args.get('name'), request.args.get('server'), aprs_pos, repeat, active, request.form.get('max_peers'), request.form.get('ip'), request.form.get('port'), enable_um, request.form.get('passphrase'), request.form.get('group_hangtime'), use_acl, request.form.get('reg_acl'), request.form.get('sub_acl'), request.form.get('ts1_acl'), request.form.get('ts2_acl'), enable_unit, request.form.get('notes'), '', '', '', '', '', '', '', public, request.form.get('other_options'), '', '')
content = '''<h3 style="text-align: center;">MASTER changed.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=manage_masters" /> '''
@ -4542,6 +4553,19 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
</select></td>
</tr>
<tr>
<td><strong>&nbsp;Use Encryption:</strong></td>
<td>&nbsp;<select name="obp_encryption">
<option selected="selected" value="False">Current - False</option>
<option value="True">True</option>
<option value="False">False</option>
</select></td>
</tr>
<td><strong>&nbsp;Encryption_key:</strong></td>
<td>&nbsp;<input name="encryption_key" type="text" value="" /></td>
</tr>
<tr>
<td><strong>&nbsp;Misc Options:</strong></td>
<td>&nbsp;<textarea id="other_options" cols="50" name="other_options" rows="4"></textarea></td>
@ -5038,6 +5062,19 @@ TG #: <strong> ''' + str(tg_d.tg) + '''</strong>
</select></td>
</tr>
<tr>
<td><strong>&nbsp;Use Encryption:</strong></td>
<td>&nbsp;<select name="obp_encryption">
<option selected="selected" value="''' + str(o.obp_encryption) + '''">Current - ''' + str(o.obp_encryption) + '''</option>
<option value="True">True</option>
<option value="False">False</option>
</select></td>
</tr>
<td><strong>&nbsp;Encryption_key:</strong></td>
<td>&nbsp;<input name="encryption_key" type="text" value="''' + str(o.encryption_key) + '''" /></td>
</tr>
<tr>
<td><strong>&nbsp;Misc Options:</strong></td>
<td>&nbsp;<textarea id="other_options" cols="50" name="other_options" rows="4">''' + str(o.other_options) + '''</textarea></td>