Skip to content

Commit

Permalink
#1618 Enhances DMR message and identifier parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Dennis Sheirer committed Aug 4, 2023
1 parent 3794eaa commit 2510e83
Show file tree
Hide file tree
Showing 16 changed files with 242 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -45,7 +45,7 @@
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.motorola.MNISProprietaryDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaProprietaryDataHeader;
import io.github.dsheirer.module.decode.dmr.message.data.header.motorola.MotorolaDataEncryptionHeader;
import io.github.dsheirer.module.decode.dmr.message.data.mbc.MBCContinuationBlock;
import io.github.dsheirer.module.decode.dmr.message.data.terminator.Terminator;
import io.github.dsheirer.module.decode.dmr.message.data.usb.USBData;
Expand Down Expand Up @@ -132,7 +132,7 @@ public static DataMessage create(DMRSyncPattern pattern, CorrectedBinaryMessage
}
else
{
MotorolaProprietaryDataHeader mprdh = new MotorolaProprietaryDataHeader(pattern,
MotorolaDataEncryptionHeader mprdh = new MotorolaDataEncryptionHeader(pattern,
payload, cach, slotType, timestamp, timeslot);
mprdh.setValid(valid);
return mprdh;
Expand Down
Expand Up @@ -78,7 +78,7 @@ public String toString()
sb.append(" RAS:").append(getBPTCReservedBits());
}

sb.append(" CSBK CAP+ SITE STATUS REST ").append(getRestChannel());
sb.append(" CSBK CAP+ SITE STATUS REST:").append(getRestChannel());
sb.append(" ").append(getSegmentIndicator());
sb.append(" ");

Expand Down
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -25,7 +25,6 @@
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.type.DefinedDataFormat;

import java.util.ArrayList;
import java.util.List;

Expand All @@ -39,6 +38,7 @@ public class DefinedShortDataHeader extends PacketSequenceHeader
private static final int RESYNCHRONIZE_FLAG = 70;
private static final int FULL_MESSAGE_FLAG = 71;
private static final int[] BIT_PADDING = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
private static final int[] HEADER_CRC = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95};

private List<Identifier> mIdentifiers;

Expand Down
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -34,6 +34,11 @@ public class ProprietaryDataHeader extends DataHeader
{
private static final int[] SERVICE_ACCESS_POINT = new int[]{0, 1, 2, 3};
private static final int[] VENDOR = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] VENDOR_DATA = new int[]{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79};
private static final int[] HEADER_CRC = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95};

/**
* Constructs an instance.
Expand Down Expand Up @@ -62,10 +67,20 @@ public String toString()
sb.append(" PROPRIETARY DATA HEADER");
sb.append(" VENDOR:").append(getVendor());
sb.append(" ").append(getServiceAccessPoint());
sb.append(" VENDOR DATA:").append(getVendorData());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}

/**
* Vendor defined data payload from this proprietary header.
* @return hex values.
*/
public String getVendorData()
{
return getMessage().getHex(VENDOR_DATA, 16);
}

/**
* Optional packet prefix.
* @return packet prefix fragment or null.
Expand Down
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -66,7 +66,8 @@ public MNISProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinaryMess
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA MNIS HEADER");
sb.append("CC:").append(getSlotType().getColorCode());
sb.append(" MOTOROLA MNIS HEADER");
if(getApplicationType() == ApplicationType.UNKNOWN)
{
sb.append(" APPLICATION TYPE:0x").append(Integer.toHexString(getApplicationTypeNumber()).toUpperCase());
Expand Down
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -31,10 +31,15 @@
/**
* Motorola Proprietary Data Header
*/
public class MotorolaProprietaryDataHeader extends ProprietaryDataHeader
public class MotorolaDataEncryptionHeader extends ProprietaryDataHeader
{
private static final int[] SERVICE_ACCESS_POINT = new int[]{0, 1, 2, 3};
private static final int[] VENDOR = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] ALGORITHM = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] KEY_ID = new int[]{24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] UNKNOWN = new int[]{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] INITIALIZATION_VECTOR = new int[]{48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79};

/**
* Constructs an instance.
Expand All @@ -46,7 +51,7 @@ public class MotorolaProprietaryDataHeader extends ProprietaryDataHeader
* @param timestamp message was received
* @param timeslot for the DMR burst
*/
public MotorolaProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinaryMessage message, CACH cach, SlotType slotType, long timestamp, int timeslot)
public MotorolaDataEncryptionHeader(DMRSyncPattern syncPattern, CorrectedBinaryMessage message, CACH cach, SlotType slotType, long timestamp, int timeslot)
{
super(syncPattern, message, cach, slotType, timestamp, timeslot);
}
Expand All @@ -55,14 +60,57 @@ public MotorolaProprietaryDataHeader(DMRSyncPattern syncPattern, CorrectedBinary
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA PROPRIETARY DATA HEADER");
sb.append(" ").append(getServiceAccessPoint());
sb.append("CC:").append(getSlotType().getColorCode());
sb.append(" MOTOROLA DATA ENCRYPTION HEADER");
sb.append(" SAP:").append(getServiceAccessPoint());
sb.append(" ALGORITHM:").append(getAlgorithm());
sb.append(" KEY:").append(getKeyId());
sb.append(" IV:").append(getInitializationVector());
sb.append(" UNK:").append(getUnknown());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}

/**
* Unknown message field(s).
* @return hex value.
*/
public String getUnknown()
{
return getMessage().getHex(UNKNOWN, 4);
}

/**
* Encryption key ID
* @return key ID
*/
public int getKeyId()
{
return getMessage().getInt(KEY_ID);
}

/**
* Encryption Algorithm
* @return algorithm ID
*/
public int getAlgorithm()
{
return getMessage().getInt(ALGORITHM);
}

/**
* Encryption initialization vector
*
* @return vector in hex
*/
public String getInitializationVector()
{
return getMessage().getHex(INITIALIZATION_VECTOR, 8);
}

/**
* Utility method to lookup the vendor from a CSBK message
*
* @param message containing CSBK bits
* @return vendor
*/
Expand Down
Expand Up @@ -37,9 +37,9 @@
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraTerminator;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraUnitToUnitVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptedVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptionParameters;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusWideAreaVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaEncryptionParameters;
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ActivityUpdateMessage;
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.CapacityPlusRestChannel;
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ConnectPlusControlChannel;
Expand Down Expand Up @@ -123,7 +123,7 @@ else if(message.size() == 96)
flc = new CapacityPlusWideAreaVoiceChannelUser(message, timestamp, timeslot);
break;
case FULL_CAPACITY_PLUS_ENCRYPTION_PARAMETERS:
flc = new CapacityPlusEncryptionParameters(message, timestamp, timeslot);
flc = new MotorolaEncryptionParameters(message, timestamp, timeslot);
break;
case FULL_HYTERA_GROUP_VOICE_CHANNEL_USER:
flc = new HyteraGroupVoiceChannelUser(message, timestamp, timeslot);
Expand Down
Expand Up @@ -27,9 +27,7 @@
import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver;
import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency;
import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio;
import io.github.dsheirer.module.decode.dmr.identifier.DMRSite;
import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup;

import java.util.ArrayList;
import java.util.List;

Expand All @@ -45,15 +43,13 @@ public class CapacityPlusWideAreaVoiceChannelUser extends CapacityPlusVoiceChann
private static final int[] GROUP_ID = new int[]{40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] UNUSED = new int[]{48, 49, 50, 51};
private static final int[] REST_LSN = new int[]{52, 53, 54, 55};
private static final int[] RADIO_ID = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final int[] SITE = new int[]{72, 73, 74, 75};
private static final int[] RADIO_ID = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75};
private static final int[] UNKNOWN_2 = new int[]{76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
93, 94, 95};

private RadioIdentifier mRadio;
private TalkgroupIdentifier mTalkgroup;
private DMRLogicalChannel mRestChannel;
private DMRSite mSite;
private List<Identifier> mIdentifiers;

/**
Expand Down Expand Up @@ -98,8 +94,6 @@ public String toString()
{
sb.append("--");
}
sb.append(" SITE:").append(getSite());
sb.append(" ").append(getServiceOptions());
sb.append(" ").append(getServiceOptions());
sb.append(" UNK1:").append(getUnknown1());
sb.append(" UNK2:").append(getUnknown2());
Expand All @@ -120,7 +114,7 @@ public String getUnknown1()
*/
public String getUnknown2()
{
return getMessage().getHex(UNKNOWN_2, 5);
return getMessage().getHex(UNKNOWN_2, 6);
}

/**
Expand Down Expand Up @@ -153,20 +147,6 @@ public boolean hasRestChannel()
return getRestLSN() != 0;
}

/**
* Site number
* @return site
*/
public DMRSite getSite()
{
if(mSite == null)
{
mSite = new DMRSite(getMessage().getInt(SITE));
}

return mSite;
}

/**
* Source radio address
*/
Expand Down
Expand Up @@ -21,33 +21,25 @@

import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.radio.RadioIdentifier;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.dmr.channel.DMRLogicalChannel;
import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver;
import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency;
import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio;
import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Motorola Capacity Plus - Encryption Parameters
* Motorola Encryption Parameters
* <p>
* Note: observed as FLC payload for a PI_HEADER slot type.
* Note: observed on a possible Hytera (clone) system that was configured as IP Site Connect compatible.
*/
public class CapacityPlusEncryptionParameters extends FullLCMessage
public class MotorolaEncryptionParameters extends FullLCMessage
{
//NOTE: field definitions are best guesses ... algorithm and key ID fields might be interchanged
private static final int[] ENCRYPTION_ALGORITHM = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] KEY_ID = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] INITIALIZATION_VECTOR = new int[]{24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55};
private static final int[] KEY_ID = new int[]{56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] ALGORITHM = new int[]{56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] DESTINATION_GROUP = new int[]{64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79};
private static final int[] UNKNOWN = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 83, 94, 95};
private static final int[] UNKNOWN = new int[]{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95};

private DMRTalkgroup mTalkgroup;
private List<Identifier> mIdentifiers;
Expand All @@ -57,7 +49,7 @@ public class CapacityPlusEncryptionParameters extends FullLCMessage
*
* @param message for the link control payload
*/
public CapacityPlusEncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot)
public MotorolaEncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot)
{
super(message, timestamp, timeslot);
}
Expand All @@ -82,11 +74,10 @@ public String toString()
sb.append(" *RESERVED-BIT*");
}

sb.append("FLC MOTOROLA CAP+ ENCRYPTION PARAMETERS - ALGORITHM:").append(getEncryptionAlgorithm());
sb.append("FLC MOTOROLA ENCRYPTION PARAMETERS - ALGORITHM:").append(getAlgorithm());
sb.append(" KEY:").append(getKeyId());
sb.append(" IV:").append(getInitializationVector());
sb.append(" TALKGROUP:").append(getTalkgroup());
sb.append(" UNK:").append(getUnknown());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}
Expand All @@ -106,9 +97,16 @@ public int getKeyId()
return getMessage().getInt(KEY_ID);
}

public int getEncryptionAlgorithm()
public String getAlgorithm()
{
return getMessage().getInt(ENCRYPTION_ALGORITHM);
int algorithm = getMessage().getInt(ALGORITHM);

if(algorithm == 0)
{
return "EP/RC4";
}

return "UNK(" + algorithm + ")";
}

public String getInitializationVector()
Expand Down

0 comments on commit 2510e83

Please sign in to comment.