Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1630 DMR FLC ARC4/EP Encryption Parameters #1631

Merged
merged 1 commit into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.TerminatorData;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.UnitToUnitVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.UnknownFullLCMessage;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraArc4EncryptionParameters;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraGroupVoiceChannelUser;
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.CapacityPlusWideAreaVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaEncryptionParameters;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaArc4EncryptionParameters;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ActivityUpdateMessage;
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.CapacityPlusRestChannel;
Expand Down Expand Up @@ -122,8 +123,34 @@ else if(message.size() == 96)
case FULL_CAPACITY_PLUS_WIDE_AREA_VOICE_CHANNEL_USER:
flc = new CapacityPlusWideAreaVoiceChannelUser(message, timestamp, timeslot);
break;
case FULL_CAPACITY_PLUS_ENCRYPTION_PARAMETERS:
flc = new MotorolaEncryptionParameters(message, timestamp, timeslot);
case FULL_ARC4_ENCRYPTION_PARAMETERS:
boolean isHytera = false;

//This is apparently now a DMR standard FLC opcode, even though it's using Motorola's vendor ID (0x10).
//As observed on a known Hytera system, it's not using the standard FLC RS-12/9/4 check, which fails.
//It's apparently using the CRC-CCITT with 0x9696 initial fill. Not sure if both Hytera and Motorola
// are using this FEC. But, by using only 16 bits for checksum versus the standad 24, they're able to
// include a full 24-bit group/radio ID in the message. For now we'll identify as either Motorola
//(using reed solomon) or Hytera (using crc-ccitt).
if(!valid)
{
int bitErrors = CRCDMR.correctCCITT80(message, 0, 80, 0x9696);

if(bitErrors < 2)
{
valid = true;
isHytera = true;
}
}

if(isHytera)
{
flc = new HyteraArc4EncryptionParameters(message, timestamp, timeslot);
}
else
{
flc = new MotorolaArc4EncryptionParameters(message, timestamp, timeslot);
}
break;
case FULL_HYTERA_GROUP_VOICE_CHANNEL_USER:
flc = new HyteraGroupVoiceChannelUser(message, timestamp, timeslot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public enum LCOpcode
//Observed on Cap+ Multi-Site System during an encrypted voice call
FULL_CAPACITY_PLUS_ENCRYPTED_VOICE_CHANNEL_USER(Vendor.MOTOROLA_CAPACITY_PLUS, true, 32, "ENCRYPTED VOICE CHANNEL USER"),
//Observed on Cap+ Multi-Site System during an encrypted voice call
FULL_CAPACITY_PLUS_ENCRYPTION_PARAMETERS(Vendor.MOTOROLA_CAPACITY_PLUS, true, 33, "ENCRYPTION PARAMETERS"),
FULL_ARC4_ENCRYPTION_PARAMETERS(Vendor.MOTOROLA_CAPACITY_PLUS, true, 33, "ARC4/EP ENCRYPTION PARAMETERS"),
//Cap+ opcodes from https://forums.radioreference.com/threads/understanding-capacity-plus-trunking-some-more.452566/
//FLCO 0: Group Call Maintenance
//FLCO 3: Private Call Maintenance (TermLC)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* *****************************************************************************
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/

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

import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
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.List;

/**
* Hytera ARC4/EP Encryption Parameters
* <p>
* Note: observed as FLC payload for a PI_HEADER slot type.
* Note: observed on a Hytera system that was configured as IP Site Connect compatible.
*/
public class HyteraArc4EncryptionParameters extends FullLCMessage
{
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[] DESTINATION_GROUP = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79};
//Hytera version uses CRC-CCITT with 0x9696 initial fill, bits: 80-95

private DMRTalkgroup mTalkgroup;
private List<Identifier> mIdentifiers;

/**
* Constructor
* @param message bits
* @param timestamp for the message
* @param timeslot of the message
*/
public HyteraArc4EncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot)
{
super(message, timestamp, timeslot);
}

@Override
public String toString()
{
StringBuilder sb = new StringBuilder();

if(!isValid())
{
sb.append("[CRC-ERROR] ");
}

if(isEncrypted())
{
sb.append(" *ENCRYPTED*");
}

if(isReservedBitSet())
{
sb.append(" *RESERVED-BIT*");
}

sb.append("FLC HYTERA ARC4/EP ENCRYPTION PARAMETERS");
sb.append(" KEY:").append(getKeyId());
sb.append(" IV:").append(getInitializationVector());
sb.append(" TALKGROUP:").append(getTalkgroup());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}

public DMRTalkgroup getTalkgroup()
{
if(mTalkgroup == null)
{
mTalkgroup = new DMRTalkgroup(getMessage().getInt(DESTINATION_GROUP));
}

return mTalkgroup;
}

public int getKeyId()
{
return getMessage().getInt(KEY_ID);
}

public String getInitializationVector()
{
return getMessage().getHex(INITIALIZATION_VECTOR, 8);
}

@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getTalkgroup());
}

return mIdentifiers;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,29 @@
import java.util.List;

/**
* Motorola Encryption Parameters
* Motorola ARC4/EP 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 MotorolaEncryptionParameters extends FullLCMessage
public class MotorolaArc4EncryptionParameters extends FullLCMessage
{
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[] 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};
//Reed Solomon FEC: 72-95
private static final int[] DESTINATION_GROUP = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
//Motorola Reed Solomon FEC bits: 72-95

private DMRTalkgroup mTalkgroup;
private List<Identifier> mIdentifiers;

/**
* Constructs an instance.
*
* @param message for the link control payload
* Constructor
* @param message bits
* @param timestamp for the message
* @param timeslot of the message
*/
public MotorolaEncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot)
public MotorolaArc4EncryptionParameters(CorrectedBinaryMessage message, long timestamp, int timeslot)
{
super(message, timestamp, timeslot);
}
Expand All @@ -74,9 +74,9 @@ public String toString()
sb.append(" *RESERVED-BIT*");
}

sb.append("FLC MOTOROLA ENCRYPTION PARAMETERS - ALGORITHM:").append(getAlgorithm());
sb.append("FLC MOTOROLA ARC4/EP ENCRYPTION PARAMETERS");
sb.append(" KEY:").append(getKeyId());
sb.append(" IV?:").append(getInitializationVector());
sb.append(" IV:").append(getInitializationVector());
sb.append(" TALKGROUP:").append(getTalkgroup());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
Expand All @@ -97,18 +97,6 @@ public int getKeyId()
return getMessage().getInt(KEY_ID);
}

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

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

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

public String getInitializationVector()
{
return getMessage().getHex(INITIALIZATION_VECTOR, 8);
Expand Down
Loading