Skip to content

Commit

Permalink
Merge pull request #1640 from DSheirer/1638-hytera-encryption-parameters
Browse files Browse the repository at this point in the history
#1638 DMR Decoder - Encryption Parameters & Hytera RRS
  • Loading branch information
DSheirer authored Aug 26, 2023
2 parents 85b2a38 + 5d7b73f commit 8fb56a5
Show file tree
Hide file tree
Showing 27 changed files with 662 additions and 291 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import io.github.dsheirer.module.decode.dmr.message.data.csbk.standard.announcement.VoteNowAdvice;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.standard.grant.ChannelGrant;
import io.github.dsheirer.module.decode.dmr.message.data.header.HeaderMessage;
import io.github.dsheirer.module.decode.dmr.message.data.header.hytera.HyteraDataEncryptionHeader;
import io.github.dsheirer.module.decode.dmr.message.data.lc.LCMessage;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.GPSInformation;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.GroupVoiceChannelUser;
Expand All @@ -74,13 +75,17 @@
import io.github.dsheirer.module.decode.dmr.message.type.ServiceOptions;
import io.github.dsheirer.module.decode.dmr.message.voice.VoiceEMBMessage;
import io.github.dsheirer.module.decode.dmr.message.voice.VoiceMessage;
import io.github.dsheirer.module.decode.dmr.message.voice.embedded.Arc4EncryptionParameters;
import io.github.dsheirer.module.decode.dmr.message.voice.embedded.EmbeddedParameters;
import io.github.dsheirer.module.decode.dmr.message.voice.embedded.EncryptionParameters;
import io.github.dsheirer.module.decode.event.DecodeEvent;
import io.github.dsheirer.module.decode.event.DecodeEventType;
import io.github.dsheirer.module.decode.event.PlottableDecodeEvent;
import io.github.dsheirer.module.decode.ip.hytera.sds.HyteraUnknownPacket;
import io.github.dsheirer.module.decode.ip.hytera.shortdata.HyteraShortDataPacket;
import io.github.dsheirer.module.decode.ip.hytera.sms.HyteraSmsPacket;
import io.github.dsheirer.module.decode.ip.mototrbo.ars.ARSPacket;
import io.github.dsheirer.module.decode.ip.mototrbo.lrrp.LRRPPacket;
import io.github.dsheirer.module.decode.ip.mototrbo.xcmp.XCMPPacket;
import io.github.dsheirer.protocol.Protocol;
import io.github.dsheirer.source.tuner.channel.rotation.AddChannelRotationActiveStateRequest;
import io.github.dsheirer.util.PacketUtil;
Expand Down Expand Up @@ -320,6 +325,32 @@ private void processPacket(DMRPacketMessage packet)
.build();
broadcast(smsEvent);
}
//Hytera Short Data - Radio Registration Service (RRS)
else if(packet.getPacket() instanceof HyteraShortDataPacket hsdp)
{
MutableIdentifierCollection mic = new MutableIdentifierCollection(packet.getIdentifiers());

StringBuilder sb = new StringBuilder();
sb.append("HYTERA");

if(hsdp.getPacketSequence().isEncrypted())
{
HyteraDataEncryptionHeader hdeh = (HyteraDataEncryptionHeader)hsdp.getPacketSequence().getProprietaryDataHeader();
sb.append(" ENCRYPTED ALGORITHM:").append(hdeh.getAlgorithm());
sb.append(" KEY:").append(hdeh.getKeyId());
sb.append(" IV:").append(hdeh.getIV());
}

sb.append(" SHORT DATA:").append(hsdp.getMessage().toHexString());


DecodeEvent shortDataEvent = DMRDecodeEvent.builder(DecodeEventType.RADIO_REGISTRATION_SERVICE, packet.getTimestamp())
.identifiers(mic)
.timeslot(getTimeslot())
.details(sb.toString())
.build();
broadcast(shortDataEvent);
}
//Unknown Hytera Long Data Service Token Message
else if(packet.getPacket() instanceof HyteraUnknownPacket hyteraUnknownPacket)
{
Expand All @@ -328,10 +359,46 @@ else if(packet.getPacket() instanceof HyteraUnknownPacket hyteraUnknownPacket)
DecodeEvent unknownTokenEvent = DMRDecodeEvent.builder(DecodeEventType.UNKNOWN_PACKET, packet.getTimestamp())
.identifiers(mic)
.timeslot(getTimeslot())
.details("HYTERA UNK TOKEN MSG:" + hyteraUnknownPacket.getHeader().toString())
.details("HYTERA LONG DATA UNK TOKEN MSG:" + hyteraUnknownPacket.getHeader().toString())
.build();
broadcast(unknownTokenEvent);
}
//Motorola ARS
else if(packet.getPacket() instanceof ARSPacket ars)
{
MutableIdentifierCollection mic = new MutableIdentifierCollection(packet.getIdentifiers());

DecodeEvent shortDataEvent = DMRDecodeEvent.builder(DecodeEventType.RADIO_REGISTRATION_SERVICE, packet.getTimestamp())
.identifiers(mic)
.timeslot(getTimeslot())
.details(ars.toString())
.build();
broadcast(shortDataEvent);
}
//Motorola LRRP
else if(packet.getPacket() instanceof LRRPPacket lrrp)
{
MutableIdentifierCollection mic = new MutableIdentifierCollection(packet.getIdentifiers());

DecodeEvent shortDataEvent = DMRDecodeEvent.builder(DecodeEventType.LRRP, packet.getTimestamp())
.identifiers(mic)
.timeslot(getTimeslot())
.details(lrrp.toString())
.build();
broadcast(shortDataEvent);
}
//Motorola XCMP
else if(packet.getPacket() instanceof XCMPPacket xcmp)
{
MutableIdentifierCollection mic = new MutableIdentifierCollection(packet.getIdentifiers());

DecodeEvent shortDataEvent = DMRDecodeEvent.builder(DecodeEventType.XCMP, packet.getTimestamp())
.identifiers(mic)
.timeslot(getTimeslot())
.details(xcmp.toString())
.build();
broadcast(shortDataEvent);
}
else
{
DecodeEvent packetEvent = DMRDecodeEvent.builder(DecodeEventType.DATA_PACKET, packet.getTimestamp())
Expand Down Expand Up @@ -380,7 +447,7 @@ private void processVoice(VoiceMessage message)
{
EmbeddedParameters embedded = voiceEmb.getEmbeddedParameters();

if(embedded.getShortBurst() instanceof Arc4EncryptionParameters arc4)
if(embedded.getShortBurst() instanceof EncryptionParameters arc4)
{
updateEncryptedCall(arc4, true, voiceEmb.getTimestamp());
}
Expand Down Expand Up @@ -972,6 +1039,15 @@ private void processLinkControl(LCMessage message, boolean isTerminator)
{
switch(message.getOpcode())
{
case FULL_ENCRYPTION_PARAMETERS:
if(message instanceof io.github.dsheirer.module.decode.dmr.message.data.lc.full.EncryptionParameters ep)
{
if(mCurrentCallEvent != null)
{
mCurrentCallEvent.setDetails(ep.getDetails());
}
}
break;
case SHORT_CAPACITY_PLUS_REST_CHANNEL_NOTIFICATION:
if(message instanceof CapacityPlusRestChannel)
{
Expand Down Expand Up @@ -1141,7 +1217,7 @@ private void processLinkControl(LCMessage message, boolean isTerminator)
* @param encryptionParameters decoded from the Voice Frame F
* @param isGroup true for group or false for individual call.
*/
private void updateEncryptedCall(Arc4EncryptionParameters encryptionParameters, boolean isGroup, long timestamp)
private void updateEncryptedCall(EncryptionParameters encryptionParameters, boolean isGroup, long timestamp)
{
if(mCurrentCallEvent != null)
{
Expand All @@ -1151,7 +1227,7 @@ private void updateEncryptedCall(Arc4EncryptionParameters encryptionParameters,
{
details = encryptionParameters.toString();
}
else if(!details.contains(encryptionParameters.toString()))
else if(!details.contains(encryptionParameters.toString()) && !details.contains("ENCRYPTION"))
{
details += " " + encryptionParameters;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
import io.github.dsheirer.module.decode.dmr.message.data.header.ConfirmedDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.DataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.DefinedShortDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.HeaderMessage;
import io.github.dsheirer.module.decode.dmr.message.data.header.MBCHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.PiHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.ProprietaryDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.RawShortDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.ResponseDataHeader;
Expand All @@ -43,7 +43,7 @@
import io.github.dsheirer.module.decode.dmr.message.data.header.UDTHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.UnconfirmedDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.VoiceHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.hytera.HyteraProprietaryDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.hytera.HyteraDataEncryptionHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MNISProprietaryDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaDataEncryptionHeader;
import io.github.dsheirer.module.decode.dmr.message.data.mbc.MBCContinuationBlock;
Expand Down Expand Up @@ -98,7 +98,7 @@ public static DataMessage create(DMRSyncPattern pattern, CorrectedBinaryMessage
return new MBCHeader(pattern, getPayload(message), cach, slotType, timestamp, timeslot);
case CHANNEL_CONTROL_ENC_HEADER:
case PI_HEADER:
return new HeaderMessage(pattern, getPayload(message), cach, slotType, timestamp, timeslot);
return new PiHeader(pattern, getPayload(message), cach, slotType, timestamp, timeslot);
case VOICE_HEADER:
return new VoiceHeader(pattern, getPayload(message), cach, slotType, timestamp, timeslot);
case DATA_ENC_HEADER:
Expand Down Expand Up @@ -138,10 +138,10 @@ public static DataMessage create(DMRSyncPattern pattern, CorrectedBinaryMessage
return mprdh;
}
case HYTERA_68:
HyteraProprietaryDataHeader hpdh = new HyteraProprietaryDataHeader(pattern, payload,
cach, slotType, timestamp, timeslot);
hpdh.setValid(valid);
return hpdh;
HyteraDataEncryptionHeader hsdh = new HyteraDataEncryptionHeader(pattern, payload,
cach, slotType, timestamp, timeslot);
hsdh.setValid(valid);
return hsdh;
default:
ProprietaryDataHeader pdh = new ProprietaryDataHeader(pattern, payload, cach,
slotType, timestamp, timeslot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*/
public abstract class DataMessageWithLinkControl extends DataMessage
{
private LCMessage mLCMessage;
protected LCMessage mLCMessage;

/**
* Constructs an instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("CC:").append(getSlotType().getColorCode());
if(hasRAS())
{
sb.append(" RAS:").append(getBPTCReservedBits());
}
if(!isValid())
{
sb.append(" [CRC ERROR]");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("CC:").append(getSlotType().getColorCode());
if(hasRAS())
{
sb.append(" RAS:").append(getBPTCReservedBits());
}
if(!isValid())
{
sb.append(" [CRC ERROR]");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("CC:").append(getSlotType().getColorCode());
if(hasRAS())
{
sb.append(" RAS:").append(getBPTCReservedBits());
}
if(!isValid())
{
sb.append(" [CRC ERROR]");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

/**
* Control Signalling Block (CSBK) Opcode enumeration
*
* ETSI TS 102 361-2 DMR Voice & Generic Services, Annex B
* ETSI TS 102 361-4 DMR Trunking Protocol, Annex B
*/
Expand Down Expand Up @@ -91,6 +90,8 @@ public enum Opcode

HYTERA_08_ACKNOWLEDGE(Vendor.HYTERA_8, 32, "HYTERA 08 ACKNOWLEDGE"),
HYTERA_08_ANNOUNCEMENT(Vendor.HYTERA_8, 40, "HYTERA 08 ANNOUNCEMENT"),
//CSBKO 44 & 47 observed on Tier3 interleaved in voice group call terminator sequence. 44 was continuously transmitted
//and 47 was only transmitted 3x times in succession in the middle of the terminators and CSBKO 44 messages.
HYTERA_08_CSBKO_44(Vendor.HYTERA_8, 44, "HYTERA 08 CSBKO 44"),
HYTERA_08_CSBKO_47(Vendor.HYTERA_8, 47, "HYTERA 08 CSBKO 47"),

Expand All @@ -104,9 +105,9 @@ public enum Opcode

UNKNOWN(Vendor.UNKNOWN, -1, "UNKNOWN");

private Vendor mVendor;
private int mValue;
private String mLabel;
private final Vendor mVendor;
private final int mValue;
private final String mLabel;

/**
* Constructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@
* ****************************************************************************
*/

package io.github.dsheirer.module.decode.dmr.message.data.header.hytera;
package io.github.dsheirer.module.decode.dmr.message.data.header;

import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.module.decode.dmr.DMRSyncPattern;
import io.github.dsheirer.module.decode.dmr.message.CACH;
import io.github.dsheirer.module.decode.dmr.message.data.SlotType;
import io.github.dsheirer.module.decode.dmr.message.data.header.ProprietaryDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.lc.LCMessage;
import io.github.dsheirer.module.decode.dmr.message.data.lc.LCMessageFactory;

/**
* Hytera Proprietary Data Header
* PI/Encryption Header with Link Control
*/
public class HyteraProprietaryDataHeader extends ProprietaryDataHeader
public class PiHeader extends HeaderMessage
{
/**
* Constructs an instance.
Expand All @@ -40,23 +41,42 @@ public class HyteraProprietaryDataHeader extends ProprietaryDataHeader
* @param timestamp message was received
* @param timeslot for the DMR burst
*/
public HyteraProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinaryMessage message, CACH cach, SlotType slotType, long timestamp, int timeslot)
public PiHeader(DMRSyncPattern syncPattern, CorrectedBinaryMessage message, CACH cach, SlotType slotType, long timestamp, int timeslot)
{
super(syncPattern, message, cach, slotType, timestamp, timeslot);
}

/**
* Access the embedded link control message
*/
public LCMessage getLCMessage()
{
if(mLCMessage == null)
{
//Overrides default to ignore opcode and construct an encryption parameters message.
mLCMessage = LCMessageFactory.createFullEncryption(getMessage(), getTimestamp(), getTimeslot());
}

return mLCMessage;
}

@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("CC:").append(getSlotType().getColorCode());

if(!isValid())
{
sb.append(" [CRC ERROR]");
}
sb.append(" HYTERA PROPRIETARY DATA HEADER");
sb.append(" SAP:").append(getServiceAccessPoint());
sb.append(" MSG:").append(getMessage().toHexString());

sb.append(getSlotType());

if(hasRAS())
{
sb.append(" RAS:").append(getBPTCReservedBits()).append(" ");
}
sb.append(" ").append(getLCMessage());
return sb.toString();
}
}
Loading

0 comments on commit 8fb56a5

Please sign in to comment.