Merge pull request #34 from duggerd/fix-3

Changes for 1.5.0 release
This commit is contained in:
Daniel Dugger 2020-08-01 11:35:07 -04:00 committed by GitHub
commit b8e8f8cddb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 2799 additions and 7526 deletions

View File

@ -10,20 +10,9 @@ Download Software: [latest release](https://github.com/KFDtool/KFDtool/releases)
Demonstration: [video](https://www.youtube.com/watch?v=Oioa3xTQoE0)
Disclaimer
----------
Software Manual: [view](doc/KFDtool_Manual.pdf)
The KFDtool as a computer peripheral has several important considerations to keep in mind when secure keyloading is required:
* The following points are only valid with unmodified software, firmware, and hardware. With physical access to the PC or adapter, the software, firmware, or hardware could be modified to covertly retain the plaintext keying material.
* Plaintext keying material is present in the PC's RAM, over the USB connection, in the adapter's RAM, and over the keyload connection. Therefore, you must trust the PC that the software is running on, or air gap it.
* It is possible that plaintext keying material in the PC's RAM is paged out to disk. It is also possible that Windows crash dumps may contain plaintext keying material. Therefore, it is recommended that the PC's hard drive is protected using full disk encryption such as BitLocker and powered off when unattended.
* After the KFDtool adapter has been disconnected from the USB port, any residual plaintext keying material present in the microcontroller's RAM will be lost.
* When certain non-default logging is enabled, plaintext keying material is written out to the log file on disk. This logging should only be enabled when diagnostic information needs to be collected, and only used with dummy keying material.
Security Considerations: [view](doc/SECURITY_CONSIDERATIONS.md)
Features
--------
@ -32,6 +21,8 @@ Features
The KFDtool software supports KFD features through the KFDtool hardware adapter (TWI/3WI/Three Wire Interface), as well as through a IP (UDP) connection (DLI/Data Link Independent interface).
Keys and groups of keys can be saved to an AES-256 encrypted key container file, which can then be selected and loaded into a target device in one operation.
Supported Manual Rekeying Features (TIA-102.AACD-A)
* 2.3.1 Keyload
@ -62,6 +53,8 @@ Key validators/generators are available for the following algorithms:
The KFDtool software only supports MR Emulator features through the KFDtool hardware adapter (TWI/3WI/Three Wire Interface) at this time.
This mode allows another keyloader to be connected to the KFDtool, and the keys retrieved.
Supported Manual Rekeying Features (TIA-102.AACD-A)
* 2.3.1 Keyload
@ -120,6 +113,7 @@ Documentation
* [TWI Cable Assembly Notes](doc/TWI_CABLE_ASSY_NOTES.md)
* [MX Connector Modification Notes](doc/MX_CONN_MOD_NOTES.md)
* [Developer Notes](doc/DEV_NOTES.md)
* [Security Considerations](doc/SECURITY_CONSIDERATIONS.md)
Contributors
------------

Binary file not shown.

BIN
doc/KFDtool_Manual.pdf Normal file

Binary file not shown.

View File

@ -0,0 +1,25 @@
# Security Considerations
* The KFDtool as a computer peripheral has several important considerations to keep in mind when secure keyloading is required.
* What this means
* Because the KFDtool keyloader is made up of a USB peripheral and software for use on a Windows PC, precautions have to be taken to preserve the integrity of the encryption keys due to the complex nature of the systems involved.
* The following points are only valid with unmodified software, firmware, and hardware. With physical access to the PC or adapter, the software, firmware, or hardware could be modified to covertly retain the plaintext keying material.
* What this means
* With physical access to the KFDtool adapter or computer running the KFDtool software, someone could modify them in a way to record or transmit the encryption keys without your knowledge. Therefore, you should physically secure the KFDtool adapter and the computer used for keyloading.
* Plaintext keying material is present in the PC's RAM, over the USB connection, in the adapter's RAM, and over the keyload connection. Therefore, you must trust the PC that the software is running on, or air gap it.
* What this means
* If the computer you use for keyloading is connected to a network, it is possible that the encryption keys could be accessed without your knowledge due to vulnerabilities in Windows or other software installed on your computer. Therefore, it is recommended that you use a computer that is not connected to any networks, and that you only install software and connect devices to it that you trust.
* It is possible that plaintext keying material in the PC's RAM is paged out to disk. It is also possible that Windows crash dumps may contain plaintext keying material. Therefore, it is recommended that the PC's hard drive is protected using full disk encryption such as BitLocker and powered off when unattended.
* What this means
* Windows is a complex operating system, and there are many ways for the encryption keys to end up on the hard drive without your knowledge. Therefore, encrypting the hard drive of the computer you use for keyloading is a good idea as it provides another layer of security against unauthorized users accessing the encryption keys without your knowledge.
* After the KFDtool adapter has been disconnected from the USB port, any residual plaintext keying material present in the microcontroller's RAM will be lost.
* What this means
* When unplugging the KFDtool adapter from the computer, any encryption keys are lost due to the memory type used. The KFDtool adapter by design does not store any encryption keys.
* When certain non-default logging is enabled, plaintext keying material is written out to the log file on disk. This logging should only be enabled when diagnostic information needs to be collected, and only used with dummy keying material.
* What this means
* There are options in the KFDtool software configuration files that can be set to write detailed information to the hard drive for use to diagnose issues. If you are directed to change these files to enable logging to diagnose an issue, understand that the keys you use may be included in these logs. Therefore, you should not use your production keys when collecting these logs.

View File

@ -1,3 +1,10 @@
KFDtool SW 1.5.0 (2020-08-01)
* Fix regression affecting MR emulation with Motorola KVL4000 (issue #31)
* Add support for key container (issue #3)
* Add manual (issue #1)
* Update NLog package version
KFDtool SW 1.4.0 (2020-05-17)
* Add support for DLI over IP devices (issue #18)

View File

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
@ -21,46 +18,6 @@ namespace KFDtool.Adapter.Bundle
private const string CANONICALIZATION_METHOD_URL = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
private const string DIGEST_METHOD_URL = "http://www.w3.org/2001/04/xmlenc#sha512";
private static byte[] Compress(byte[] data)
{
byte[] buffer = data;
var memoryStream = new MemoryStream();
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gZipStream.Write(buffer, 0, buffer.Length);
}
memoryStream.Position = 0;
var compressedData = new byte[memoryStream.Length];
memoryStream.Read(compressedData, 0, compressedData.Length);
var gZipBuffer = new byte[compressedData.Length + 4];
Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
return gZipBuffer;
}
private static byte[] Decompress(byte[] data)
{
byte[] gZipBuffer = data;
using (var memoryStream = new MemoryStream())
{
int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4);
var buffer = new byte[dataLength];
memoryStream.Position = 0;
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
gZipStream.Read(buffer, 0, buffer.Length);
}
return buffer;
}
}
private static string GetDigest(XmlDocument doc)
{
XmlDsigC14NTransform t = new XmlDsigC14NTransform();
@ -233,7 +190,7 @@ namespace KFDtool.Adapter.Bundle
// write uncompressed firmware package file
File.WriteAllBytes(outPath + ".ufp", pkgData);
byte[] outData = Compress(pkgData);
byte[] outData = Shared.Utility.Compress(pkgData);
// write compressed firmware package file
File.WriteAllBytes(outPath + ".cfp", outData);
@ -243,7 +200,7 @@ namespace KFDtool.Adapter.Bundle
{
byte[] inData = File.ReadAllBytes(inPath);
byte[] pkgData = Decompress(inData);
byte[] pkgData = Shared.Utility.Decompress(inData);
return OpenUpdatePackage(pkgData);
}

View File

@ -34,7 +34,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.1\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.7.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@ -68,6 +68,10 @@
<Project>{d483bc8d-0a84-4fa3-a196-3d15ad219dae}</Project>
<Name>KFDtool.BSL430</Name>
</ProjectReference>
<ProjectReference Include="..\KFDtool.Shared\KFDtool.Shared.csproj">
<Project>{d6e45b54-c02b-4b24-ba1d-d06838071a81}</Project>
<Name>KFDtool.Shared</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.1" targetFramework="net472" />
<package id="NLog" version="4.7.3" targetFramework="net472" />
</packages>

View File

@ -34,7 +34,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.1\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.7.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.1" targetFramework="net472" />
<package id="NLog" version="4.7.3" targetFramework="net472" />
</packages>

View File

@ -43,7 +43,7 @@
<HintPath>..\packages\Mono.Options.6.6.0.161\lib\net40\Mono.Options.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.1\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.7.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@ -69,9 +69,6 @@
<Content Include="NLog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="NLog.xsd">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]
[assembly: AssemblyInformationalVersion("1.5.0")]

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Mono.Options" version="6.6.0.161" targetFramework="net472" />
<package id="NLog" version="4.7.1" targetFramework="net472" />
<package id="NLog.Schema" version="4.7.1" targetFramework="net472" />
<package id="NLog" version="4.7.3" targetFramework="net472" />
</packages>

View File

@ -0,0 +1,350 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
namespace KFDtool.Container
{
public class ContainerUtilities
{
public static byte[] GenerateSalt(int saltLength)
{
byte[] salt = new byte[saltLength];
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(salt);
}
return salt;
}
public static byte[] Pbkdf2DeriveKeyFromPassword(string password, byte[] salt, int iterationCount, string hashAlgorithm, int keyLength)
{
Rfc2898DeriveBytes pbkdf2;
if (hashAlgorithm == "SHA512")
{
pbkdf2 = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), salt, iterationCount, HashAlgorithmName.SHA512);
}
else
{
throw new Exception(string.Format("invalid hash algorithm: {0}", hashAlgorithm));
}
return pbkdf2.GetBytes(keyLength);
}
public static InnerContainer CreateInnerContainer()
{
InnerContainer innerContainer = new InnerContainer();
innerContainer.Version = "1.0";
innerContainer.Keys = new ObservableCollection<KeyItem>();
innerContainer.NextKeyNumber = 1;
innerContainer.Groups = new ObservableCollection<GroupItem>();
innerContainer.NextGroupNumber = 1;
return innerContainer;
}
public static XmlDocument SerializeInnerContainer(InnerContainer innerContainer)
{
XmlDocument doc = new XmlDocument();
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.InsertBefore(xmlDeclaration, doc.DocumentElement);
XPathNavigator nav = doc.CreateNavigator();
using (XmlWriter w = nav.AppendChild())
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty); // remove xsd and xsi attributes
XmlSerializer s = new XmlSerializer(typeof(InnerContainer));
s.Serialize(w, innerContainer, ns);
}
return doc;
}
public static (OuterContainer Container, byte[] Key) CreateOuterContainer(string password)
{
string outerVersion = "1.0";
int saltLength = 32; // critical security parameter
int iterationCount = 100000; // critical security parameter
string hashAlgorithm = "SHA512"; // critical security parameter
int keyLength = 32; // critical security parameter
byte[] salt = GenerateSalt(saltLength);
byte[] key = Pbkdf2DeriveKeyFromPassword(password, salt, iterationCount, hashAlgorithm, keyLength);
OuterContainer outerContainer = new OuterContainer();
outerContainer.Version = outerVersion;
outerContainer.KeyDerivation = new KeyDerivation();
outerContainer.KeyDerivation.DerivationAlgorithm = "PBKDF2";
outerContainer.KeyDerivation.HashAlgorithm = hashAlgorithm;
outerContainer.KeyDerivation.Salt = salt;
outerContainer.KeyDerivation.IterationCount = iterationCount;
outerContainer.KeyDerivation.KeyLength = keyLength;
outerContainer.EncryptedDataPlaceholder = "placeholder";
return (outerContainer, key);
}
public static XmlDocument SerializeOuterContainer(OuterContainer outerContainer)
{
XmlDocument doc = new XmlDocument();
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.InsertBefore(xmlDeclaration, doc.DocumentElement);
XPathNavigator nav = doc.CreateNavigator();
using (XmlWriter w = nav.AppendChild())
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty); // remove xsd and xsi attributes
XmlSerializer s = new XmlSerializer(typeof(OuterContainer));
s.Serialize(w, outerContainer, ns);
}
return doc;
}
public static byte[] EncryptOuterContainer(OuterContainer outerContainer, InnerContainer innerContainer, byte[] key)
{
XmlDocument outerContainerXml = SerializeOuterContainer(outerContainer);
XmlDocument innerContainerXml = SerializeInnerContainer(innerContainer);
XmlElement encryptedDataPlaceholder = outerContainerXml.GetElementsByTagName("EncryptedDataPlaceholder")[0] as XmlElement;
XmlElement plaintextInnerContainer = innerContainerXml.GetElementsByTagName("InnerContainer")[0] as XmlElement;
EncryptedData encryptedData = new EncryptedData();
encryptedData.Type = EncryptedXml.XmlEncElementUrl;
encryptedData.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
EncryptedXml encryptedXml = new EncryptedXml();
using (AesCryptoServiceProvider aesCsp = new AesCryptoServiceProvider())
{
aesCsp.KeySize = 256; // critical security parameter
aesCsp.Key = key; // critical security parameter
aesCsp.Mode = CipherMode.CBC; // critical security parameter
aesCsp.GenerateIV(); // critical security parameter
encryptedData.CipherData.CipherValue = encryptedXml.EncryptData(plaintextInnerContainer, aesCsp, false);
}
EncryptedXml.ReplaceElement(encryptedDataPlaceholder, encryptedData, false);
byte[] outerContainerBytes = Encoding.UTF8.GetBytes(outerContainerXml.OuterXml);
byte[] fileBytes = Shared.Utility.Compress(outerContainerBytes);
return fileBytes;
}
public static (OuterContainer ContainerOuter, InnerContainer ContainerInner, byte[] Key) DecryptOuterContainer(byte[] fileBytes, string password)
{
byte[] outerContainerBytes;
try
{
outerContainerBytes = Shared.Utility.Decompress(fileBytes);
}
catch (Exception ex)
{
throw new Exception(string.Format("failed to decompress (corrupted or not a valid container file): {0}", ex.Message));
}
XmlDocument outerContainerXml = new XmlDocument();
outerContainerXml.LoadXml(Encoding.UTF8.GetString(outerContainerBytes));
string version;
try
{
version = outerContainerXml.SelectSingleNode("/OuterContainer/@version").Value;
}
catch (Exception ex)
{
throw new Exception(string.Format("unable to read /OuterContainer/@version: {0}", ex.Message));
}
Version parsedVersion = new Version(version);
if (parsedVersion.Major != 1)
{
throw new Exception(string.Format("outer container version too new (this container was written on a newer software version) - expected 1, got {0}", parsedVersion.Major));
}
OuterContainer outerContainer = new OuterContainer();
string outerVersion = "1.0";
outerContainer.Version = outerVersion;
outerContainer.KeyDerivation = new KeyDerivation();
byte[] key;
string derivationAlgorithm;
try
{
derivationAlgorithm = outerContainerXml.SelectSingleNode("/OuterContainer/KeyDerivation/DerivationAlgorithm").InnerText;
}
catch (Exception ex)
{
throw new Exception(string.Format("invalid KeyDerivation DerivationAlgorithm: {0}", ex.Message));
}
outerContainer.KeyDerivation.DerivationAlgorithm = derivationAlgorithm;
if (derivationAlgorithm == "PBKDF2")
{
string hashAlgorithm;
try
{
hashAlgorithm = outerContainerXml.SelectSingleNode("/OuterContainer/KeyDerivation/HashAlgorithm").InnerText;
}
catch (Exception ex)
{
throw new Exception(string.Format("invalid KeyDerivation HashAlgorithm: {0}", ex.Message));
}
outerContainer.KeyDerivation.HashAlgorithm = hashAlgorithm;
byte[] salt;
try
{
salt = Convert.FromBase64String(outerContainerXml.SelectSingleNode("/OuterContainer/KeyDerivation/Salt").InnerText);
}
catch (Exception ex)
{
throw new Exception(string.Format("invalid KeyDerivation Salt: {0}", ex.Message));
}
outerContainer.KeyDerivation.Salt = salt;
int iterationCount;
try
{
iterationCount = Convert.ToInt32(outerContainerXml.SelectSingleNode("/OuterContainer/KeyDerivation/IterationCount").InnerText);
}
catch (Exception ex)
{
throw new Exception(string.Format("invalid KeyDerivation IterationCount: {0}", ex.Message));
}
outerContainer.KeyDerivation.IterationCount = iterationCount;
int keyLength;
try
{
keyLength = Convert.ToInt32(outerContainerXml.SelectSingleNode("/OuterContainer/KeyDerivation/KeyLength").InnerText);
}
catch (Exception ex)
{
throw new Exception(string.Format("invalid KeyDerivation KeyLength: {0}", ex.Message));
}
outerContainer.KeyDerivation.KeyLength = keyLength;
key = Pbkdf2DeriveKeyFromPassword(password, salt, iterationCount, hashAlgorithm, keyLength);
}
else
{
throw new Exception(string.Format("unsupported KeyDerivation DerivationAlgorithm: {0}", derivationAlgorithm));
}
outerContainer.EncryptedDataPlaceholder = "placeholder";
XmlElement encryptedDataElement = outerContainerXml.GetElementsByTagName("EncryptedData")[0] as XmlElement;
if (encryptedDataElement == null)
{
throw new Exception("unable to find EncryptedData");
}
EncryptedData encryptedData = new EncryptedData();
encryptedData.LoadXml(encryptedDataElement);
EncryptedXml encryptedXml = new EncryptedXml();
byte[] innerContainerBytes;
using (AesCryptoServiceProvider aesCsp = new AesCryptoServiceProvider())
{
aesCsp.KeySize = 256; // critical security parameter
aesCsp.Key = key; // critical security parameter
aesCsp.Mode = CipherMode.CBC; // critical security parameter
aesCsp.GenerateIV(); // critical security parameter
try
{
innerContainerBytes = encryptedXml.DecryptData(encryptedData, aesCsp);
}
catch (Exception ex)
{
throw new Exception(string.Format("unable to decrypt InnerContainer (check password): {0}", ex.Message));
}
}
XmlDocument innerContainerXml = new XmlDocument();
try
{
innerContainerXml.LoadXml(Encoding.UTF8.GetString(innerContainerBytes));
}
catch (Exception ex)
{
throw new Exception(string.Format("unable to parse InnerContainer (check password): {0}", ex.Message));
}
string innerReadVersion;
try
{
innerReadVersion = innerContainerXml.SelectSingleNode("/InnerContainer/@version").Value;
}
catch (Exception ex)
{
throw new Exception(string.Format("unable to read /InnerContainer/@version: {0}", ex.Message));
}
Version innerReadVersionParsed = new Version(innerReadVersion);
if (innerReadVersionParsed.Major != 1)
{
throw new Exception(string.Format("inner container version too new (this container was written on a newer software version) - expected 1, got {0}", innerReadVersionParsed.Major));
}
InnerContainer innerContainer;
using (XmlReader xmlReader = new XmlNodeReader(innerContainerXml))
{
try
{
innerContainer = (InnerContainer)new XmlSerializer(typeof(InnerContainer)).Deserialize(xmlReader);
}
catch (Exception ex)
{
throw new Exception(string.Format("unable to deserialize InnerContainer: {0}", ex.Message));
}
}
return (outerContainer, innerContainer, key);
}
}
}

View File

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.ComponentModel;
namespace KFDtool.Container
{
public class GroupItem : INotifyPropertyChanged
{
public int Id { get; set; }
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
NotifyPropertyChanged("Name");
}
}
}
public List<int> Keys { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public override string ToString()
{
return Name.ToString();
}
}
}

View File

@ -0,0 +1,19 @@
using System.Collections.ObjectModel;
using System.Xml.Serialization;
namespace KFDtool.Container
{
public class InnerContainer
{
[XmlAttribute("version")]
public string Version { get; set; }
public ObservableCollection<KeyItem> Keys { get; set; }
public int NextKeyNumber { get; set; }
public ObservableCollection<GroupItem> Groups { get; set; }
public int NextGroupNumber { get; set; }
}
}

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4E99EC83-6EE7-49E0-A9AF-6674A53F578C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>KFDtool.Container</RootNamespace>
<AssemblyName>KFDtool.Container</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Security" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ContainerUtilities.cs" />
<Compile Include="GroupItem.cs" />
<Compile Include="InnerContainer.cs" />
<Compile Include="KeyDerivation.cs" />
<Compile Include="KeyItem.cs" />
<Compile Include="OuterContainer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\KFDtool.Shared\KFDtool.Shared.csproj">
<Project>{d6e45b54-c02b-4b24-ba1d-d06838071a81}</Project>
<Name>KFDtool.Shared</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,15 @@
namespace KFDtool.Container
{
public class KeyDerivation
{
public string DerivationAlgorithm { get; set; }
public string HashAlgorithm { get; set; }
public byte[] Salt { get; set; }
public int IterationCount { get; set; }
public int KeyLength { get; set; }
}
}

View File

@ -0,0 +1,59 @@
using System.ComponentModel;
namespace KFDtool.Container
{
public class KeyItem : INotifyPropertyChanged
{
public int Id { get; set; }
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
NotifyPropertyChanged("Name");
}
}
}
public bool ActiveKeyset { get; set; }
public int KeysetId { get; set; }
public int Sln { get; set; }
public bool KeyTypeAuto { get; set; }
public bool KeyTypeTek { get; set; }
public bool KeyTypeKek { get; set; }
public int KeyId { get; set; }
public int AlgorithmId { get; set; }
public string Key { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public override string ToString()
{
return Name.ToString();
}
}
}

View File

@ -0,0 +1,14 @@
using System.Xml.Serialization;
namespace KFDtool.Container
{
public class OuterContainer
{
[XmlAttribute("version")]
public string Version { get; set; }
public KeyDerivation KeyDerivation { get; set; }
public string EncryptedDataPlaceholder { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("KFDtool.Container")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("KFDtool")]
[assembly: AssemblyCopyright("Copyright 2019-2020 Daniel Dugger")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4e99ec83-6ee7-49e0-a9af-6674a53f578c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.3" targetFramework="net472" />
</packages>

View File

@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using NLog;
using System;
using System.Windows;
namespace KFDtool.Gui
@ -13,5 +9,20 @@ namespace KFDtool.Gui
/// </summary>
public partial class App : Application
{
private static Logger Log = LogManager.GetCurrentClassLogger();
public App()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
Log.Error("UnhandledException caught: {0}", ex.Message);
Log.Error("UnhandledException StackTrace: {0}", ex.StackTrace);
Log.Fatal("Runtime terminating: {0}", e.IsTerminating);
}
}
}

View File

@ -38,7 +38,7 @@ namespace KFDtool.Gui.Control
private void StartEmulation()
{
Settings.InProgressScreen = "NavigateP25MrEmulator";
Settings.ScreenInProgress = true;
StartButton.IsEnabled = false;
StopButton.IsEnabled = true;
@ -48,7 +48,7 @@ namespace KFDtool.Gui.Control
private void StopEmulation()
{
Settings.InProgressScreen = string.Empty;
Settings.ScreenInProgress = false;
StartButton.IsEnabled = true;
StopButton.IsEnabled = false;

View File

@ -0,0 +1,26 @@
<UserControl x:Class="KFDtool.Gui.Control.P25MultipleKeyload"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:KFDtool.Gui.Control"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Label Content="Keys" HorizontalAlignment="Left" Margin="183,5,0,0" VerticalAlignment="Top"/>
<Label Content="Available" HorizontalAlignment="Left" Margin="56,23,0,0" VerticalAlignment="Top"/>
<Label Content="Selected" HorizontalAlignment="Left" Margin="285,23,0,0" VerticalAlignment="Top"/>
<ListBox Name="lbKeysAvailable" DisplayMemberPath="Value" HorizontalAlignment="Left" Height="275" Margin="19,54,0,0" VerticalAlignment="Top" Width="140"/>
<Button Content="Add &gt;" HorizontalAlignment="Left" Margin="164,163,0,0" VerticalAlignment="Top" Width="75" Click="Keys_Add_Click"/>
<Button Content="&lt; Remove" HorizontalAlignment="Left" Margin="164,195,0,0" VerticalAlignment="Top" Width="75" Click="Keys_Remove_Click"/>
<ListBox Name="lbKeysSelected" DisplayMemberPath="Value" HorizontalAlignment="Left" Height="275" Margin="244,54,0,0" VerticalAlignment="Top" Width="140"/>
<Label Content="Groups" HorizontalAlignment="Left" Margin="556,5,0,0" VerticalAlignment="Top"/>
<Label Content="Available" HorizontalAlignment="Left" Margin="438,23,0,0" VerticalAlignment="Top"/>
<Label Content="Selected" HorizontalAlignment="Left" Margin="668,23,0,0" VerticalAlignment="Top"/>
<ListBox Name="lbGroupsAvailable" DisplayMemberPath="Value" HorizontalAlignment="Left" Height="275" Margin="399,54,0,0" VerticalAlignment="Top" Width="140"/>
<Button Content="Add &gt;" HorizontalAlignment="Left" Margin="544,163,0,0" VerticalAlignment="Top" Width="75" Click="Groups_Add_Click"/>
<Button Content="&lt; Remove" HorizontalAlignment="Left" Margin="544,195,0,0" VerticalAlignment="Top" Width="75" Click="Groups_Remove_Click"/>
<ListBox Name="lbGroupsSelected" DisplayMemberPath="Value" HorizontalAlignment="Left" Height="275" Margin="624,54,0,0" VerticalAlignment="Top" Width="140"/>
<Button Content="Load" HorizontalAlignment="Left" Margin="355,345,0,0" VerticalAlignment="Top" Width="75" Click="Load_Click"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,272 @@
using KFDtool.Container;
using KFDtool.P25.TransferConstructs;
using KFDtool.Shared;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace KFDtool.Gui.Control
{
/// <summary>
/// Interaction logic for P25MultipleKeyload.xaml
/// </summary>
public partial class P25MultipleKeyload : UserControl
{
private static NLog.Logger Log = NLog.LogManager.GetCurrentClassLogger();
private List<int> Keys;
private List<int> Groups;
private Dictionary<int, string> KeysAvailable;
private Dictionary<int, string> KeysSelected;
private Dictionary<int, string> GroupsAvailable;
private Dictionary<int, string> GroupsSelected;
public P25MultipleKeyload()
{
InitializeComponent();
Keys = new List<int>();
Groups = new List<int>();
KeysAvailable = new Dictionary<int, string>();
KeysSelected = new Dictionary<int, string>();
GroupsAvailable = new Dictionary<int, string>();
GroupsSelected = new Dictionary<int, string>();
lbKeysAvailable.ItemsSource = KeysAvailable;
lbKeysSelected.ItemsSource = KeysSelected;
lbGroupsAvailable.ItemsSource = GroupsAvailable;
lbGroupsSelected.ItemsSource = GroupsSelected;
UpdateKeysColumns();
UpdateGroupsColumns();
}
private void UpdateKeysColumns()
{
KeysAvailable.Clear();
foreach (KeyItem keyItem in Settings.ContainerInner.Keys)
{
KeysAvailable.Add(keyItem.Id, keyItem.Name);
}
KeysSelected.Clear();
foreach (int key in Keys)
{
KeysSelected.Add(key, KeysAvailable[key]);
}
foreach (KeyValuePair<int, string> selected in KeysSelected)
{
KeysAvailable.Remove(selected.Key);
}
lbKeysAvailable.Items.Refresh();
lbKeysSelected.Items.Refresh();
}
private void UpdateGroupsColumns()
{
GroupsAvailable.Clear();
foreach (Container.GroupItem groupItem in Settings.ContainerInner.Groups)
{
GroupsAvailable.Add(groupItem.Id, groupItem.Name);
}
GroupsSelected.Clear();
foreach (int group in Groups)
{
GroupsSelected.Add(group, GroupsAvailable[group]);
}
foreach (KeyValuePair<int, string> selected in GroupsSelected)
{
GroupsAvailable.Remove(selected.Key);
}
lbGroupsAvailable.Items.Refresh();
lbGroupsSelected.Items.Refresh();
}
private void Keys_Add_Click(object sender, RoutedEventArgs e)
{
if (lbKeysAvailable.SelectedItem != null)
{
int key = ((KeyValuePair<int, string>)lbKeysAvailable.SelectedItem).Key;
Keys.Add(key);
UpdateKeysColumns();
}
}
private void Keys_Remove_Click(object sender, RoutedEventArgs e)
{
if (lbKeysSelected.SelectedItem != null)
{
int key = ((KeyValuePair<int, string>)lbKeysSelected.SelectedItem).Key;
Keys.Remove(key);
UpdateKeysColumns();
}
}
private void Groups_Add_Click(object sender, RoutedEventArgs e)
{
if (lbGroupsAvailable.SelectedItem != null)
{
int key = ((KeyValuePair<int, string>)lbGroupsAvailable.SelectedItem).Key;
Groups.Add(key);
UpdateGroupsColumns();
}
}
private void Groups_Remove_Click(object sender, RoutedEventArgs e)
{
if (lbGroupsSelected.SelectedItem != null)
{
int key = ((KeyValuePair<int, string>)lbGroupsSelected.SelectedItem).Key;
Groups.Remove(key);
UpdateGroupsColumns();
}
}
private void Load()
{
List<int> combinedKeys = new List<int>();
combinedKeys.AddRange(Keys);
foreach (int groupItemId in Groups)
{
bool found = false;
foreach (Container.GroupItem containerGroupItem in Settings.ContainerInner.Groups)
{
if (groupItemId == containerGroupItem.Id)
{
found = true;
combinedKeys.AddRange(containerGroupItem.Keys);
break;
}
}
if (!found)
{
throw new Exception(string.Format("group with id {0} not found in container", groupItemId));
}
}
if (combinedKeys.Count == 0)
{
throw new Exception("no keys/groups selected");
}
List<CmdKeyItem> keys = new List<CmdKeyItem>();
foreach (int keyId in combinedKeys)
{
bool found = false;
foreach (KeyItem containerKeyItem in Settings.ContainerInner.Keys)
{
if (keyId == containerKeyItem.Id)
{
found = true;
CmdKeyItem cmdKeyItem = new CmdKeyItem();
cmdKeyItem.UseActiveKeyset = containerKeyItem.ActiveKeyset;
cmdKeyItem.KeysetId = containerKeyItem.KeysetId;
cmdKeyItem.Sln = containerKeyItem.Sln;
if (containerKeyItem.KeyTypeAuto)
{
if (cmdKeyItem.Sln >= 0 && cmdKeyItem.Sln <= 61439)
{
cmdKeyItem.IsKek = false;
}
else if (cmdKeyItem.Sln >= 61440 && cmdKeyItem.Sln <= 65535)
{
cmdKeyItem.IsKek = true;
}
else
{
throw new Exception(string.Format("invalid Sln and KeyTypeAuto set: {0}", cmdKeyItem.Sln));
}
}
else if (containerKeyItem.KeyTypeTek)
{
cmdKeyItem.IsKek = false;
}
else if (containerKeyItem.KeyTypeKek)
{
cmdKeyItem.IsKek = true;
}
else
{
throw new Exception("KeyTypeAuto, KeyTypeTek, and KeyTypeKek all false");
}
cmdKeyItem.KeyId = containerKeyItem.KeyId;
cmdKeyItem.AlgorithmId = containerKeyItem.AlgorithmId;
cmdKeyItem.Key = Utility.ByteStringToByteList(containerKeyItem.Key);
keys.Add(cmdKeyItem);
break;
}
}
if (!found)
{
throw new Exception(string.Format("key with id {0} not found in container", keyId));
}
}
Interact.Keyload(Settings.SelectedDevice, keys);
}
private void Load_Click(object sender, RoutedEventArgs e)
{
try
{
Load();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Error -- {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
MessageBox.Show("Key(s) Loaded Successfully", "Information", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}

View File

@ -0,0 +1,40 @@
<Window x:Class="KFDtool.Gui.Dialog.ContainerEdit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:KFDtool.Gui.Dialog"
mc:Ignorable="d"
Title="Edit Container" Height="600" Width="950" MinHeight="600" MinWidth="950" WindowStartupLocation="CenterOwner"
Closing="ContainerEdit_Closing">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<DockPanel>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Bottom" Margin="0,5,0,5">
<Button Content="New" Click="New_Click" Padding="5,0,5,0" Margin="0,0,5,0" />
<Button Content="Up" Click="Up_Click" Padding="5,0,5,0" Margin="0,0,5,0" />
<Button Content="Down" Click="Down_Click" Padding="5,0,5,0" Margin="0,0,5,0" />
<Button Content="Delete" Click="Delete_Click" Padding="5,0,5,0" Margin="0,0,0,0" />
</StackPanel>
<TabControl Name="containerTabControl" SelectionChanged="Tab_SelectionChanged">
<TabItem Name="keysTabItem" Header="Keys">
<ListView x:Name="keysListView" DisplayMemberPath="Name" />
</TabItem>
<TabItem Name="groupsTabItem" Header="Groups">
<ListView x:Name="groupsListView" DisplayMemberPath="Name" />
</TabItem>
</TabControl>
</DockPanel>
</Grid>
<Grid Grid.Row="0" Grid.Column="1">
<ContentControl Name="ItemView"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,200 @@
using KFDtool.Container;
using KFDtool.P25.Generator;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace KFDtool.Gui.Dialog
{
/// <summary>
/// Interaction logic for ContainerEdit.xaml
/// </summary>
public partial class ContainerEdit : Window
{
private string OriginalContainer;
public ContainerEdit()
{
InitializeComponent();
OriginalContainer = ContainerUtilities.SerializeInnerContainer(Settings.ContainerInner).OuterXml;
keysListView.ItemsSource = Settings.ContainerInner.Keys;
keysListView.SelectionChanged += KeysListView_SelectionChanged;
groupsListView.ItemsSource = Settings.ContainerInner.Groups;
groupsListView.SelectionChanged += GroupsListView_SelectionChanged;
}
private void Tab_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
keysListView.SelectedItem = null;
groupsListView.SelectedItem = null;
}
}
private void KeysListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (keysListView.SelectedItem != null)
{
ContainerEditKeyControl keyEdit = new ContainerEditKeyControl((KeyItem)keysListView.SelectedItem);
ItemView.Content = keyEdit;
}
else
{
ItemView.Content = null;
}
}
private void GroupsListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (groupsListView.SelectedItem != null)
{
ContainerEditGroupControl keyEdit = new ContainerEditGroupControl((Container.GroupItem)groupsListView.SelectedItem);
ItemView.Content = keyEdit;
}
else
{
ItemView.Content = null;
}
}
void ContainerEdit_Closing(object sender, CancelEventArgs e)
{
string currentContainer = ContainerUtilities.SerializeInnerContainer(Settings.ContainerInner).OuterXml;
if (OriginalContainer != currentContainer)
{
Settings.ContainerSaved = false;
}
}
private void New_Click(object sender, RoutedEventArgs e)
{
if (containerTabControl.SelectedItem == keysTabItem)
{
KeyItem key = new KeyItem();
key.Id = Settings.ContainerInner.NextKeyNumber;
key.Name = string.Format("Key {0}", Settings.ContainerInner.NextKeyNumber);
Settings.ContainerInner.NextKeyNumber++;
key.ActiveKeyset = true;
key.KeysetId = 1;
key.Sln = 1;
key.KeyTypeAuto = true;
key.KeyTypeTek = false;
key.KeyTypeKek = false;
key.KeyId = 1;
key.AlgorithmId = 0x84;
key.Key = BitConverter.ToString(KeyGenerator.GenerateVarKey(32).ToArray()).Replace("-", string.Empty);
Settings.ContainerInner.Keys.Add(key);
}
else if (containerTabControl.SelectedItem == groupsTabItem)
{
Container.GroupItem group = new Container.GroupItem();
group.Id = Settings.ContainerInner.NextGroupNumber;
group.Name = string.Format("Group {0}", Settings.ContainerInner.NextGroupNumber);
Settings.ContainerInner.NextGroupNumber++;
group.Keys = new List<int>();
Settings.ContainerInner.Groups.Add(group);
}
}
private void Up_Click(object sender, RoutedEventArgs e)
{
if (containerTabControl.SelectedItem == keysTabItem)
{
if (keysListView.SelectedItem != null)
{
int index = keysListView.SelectedIndex;
if (index - 1 >= 0)
{
Settings.ContainerInner.Keys.Move(index, index - 1);
}
}
}
else if (containerTabControl.SelectedItem == groupsTabItem)
{
if (groupsListView.SelectedItem != null)
{
int index = groupsListView.SelectedIndex;
if (index - 1 >= 0)
{
Settings.ContainerInner.Groups.Move(index, index - 1);
}
}
}
}
private void Down_Click(object sender, RoutedEventArgs e)
{
if (containerTabControl.SelectedItem == keysTabItem)
{
if (keysListView.SelectedItem != null)
{
int index = keysListView.SelectedIndex;
if (index + 1 < Settings.ContainerInner.Keys.Count)
{
Settings.ContainerInner.Keys.Move(index, index + 1);
}
}
}
else if (containerTabControl.SelectedItem == groupsTabItem)
{
if (groupsListView.SelectedItem != null)
{
int index = groupsListView.SelectedIndex;
if (index + 1 < Settings.ContainerInner.Groups.Count)
{
Settings.ContainerInner.Groups.Move(index, index + 1);
}
}
}
}
private void Delete_Click(object sender, RoutedEventArgs e)
{
if (containerTabControl.SelectedItem == keysTabItem)
{
if (keysListView.SelectedItem != null)
{
int index = keysListView.SelectedIndex;
int id = Settings.ContainerInner.Keys[index].Id;
// remove key reference from groups
foreach (Container.GroupItem groupItem in Settings.ContainerInner.Groups)
{
if (groupItem.Keys.Contains(id))
{
groupItem.Keys.Remove(id);
}
}
// remove key item
Settings.ContainerInner.Keys.RemoveAt(index);
}
}
else if (containerTabControl.SelectedItem == groupsTabItem)
{
if (groupsListView.SelectedItem != null)
{
int index = groupsListView.SelectedIndex;
Settings.ContainerInner.Groups.RemoveAt(index);
}
}
}
}
}

View File

@ -0,0 +1,20 @@
<UserControl x:Class="KFDtool.Gui.Dialog.ContainerEditGroupControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:KFDtool.Gui.Dialog"
mc:Ignorable="d"
d:DesignHeight="550" d:DesignWidth="685">
<Grid>
<Label Content="Name" HorizontalAlignment="Left" Margin="10,24,0,0" VerticalAlignment="Top"/>
<TextBox Name="txtName" HorizontalAlignment="Left" Height="23" Margin="85,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="258"/>
<Label Content="Available" HorizontalAlignment="Left" Margin="154,57,0,0" VerticalAlignment="Top"/>
<ListBox Name="lbAvailable" DisplayMemberPath="Value" HorizontalAlignment="Left" Height="400" Margin="85,88,0,0" VerticalAlignment="Top" Width="200"/>
<Button Content="Add &gt;" Click="Add_Button_Click" HorizontalAlignment="Left" Margin="309,240,0,0" VerticalAlignment="Top" Width="74"/>
<Button Content="&lt; Remove" Click="Remove_Button_Click" HorizontalAlignment="Left" Margin="309,272,0,0" VerticalAlignment="Top" Width="75"/>
<Label Content="Selected" HorizontalAlignment="Left" Margin="482,57,0,0" VerticalAlignment="Top"/>
<ListBox Name="lbSelected" DisplayMemberPath="Value" HorizontalAlignment="Left" Height="400" Margin="406,88,0,0" VerticalAlignment="Top" Width="200"/>
<Button Content="Save" HorizontalAlignment="Left" Click="Save_Button_Click" Margin="309,505,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,118 @@
using KFDtool.Container;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace KFDtool.Gui.Dialog
{
/// <summary>
/// Interaction logic for ContainerEditGroupControl.xaml
/// </summary>
public partial class ContainerEditGroupControl : UserControl
{
private Container.GroupItem LocalGroup { get; set; }
private List<int> Keys;
private Dictionary<int, string> Available;
private Dictionary<int, string> Selected;
public ContainerEditGroupControl(Container.GroupItem groupItem)
{
InitializeComponent();
LocalGroup = groupItem;
Keys = new List<int>();
Keys.AddRange(groupItem.Keys);
Available = new Dictionary<int, string>();
Selected = new Dictionary<int, string>();
txtName.Text = groupItem.Name;
lbAvailable.ItemsSource = Available;
lbSelected.ItemsSource = Selected;
UpdateColumns();
}
private void UpdateColumns()
{
Available.Clear();
foreach (KeyItem keyItem in Settings.ContainerInner.Keys)
{
Available.Add(keyItem.Id, keyItem.Name);
}
Selected.Clear();
foreach (int key in Keys)
{
Selected.Add(key, Available[key]);
}
foreach (KeyValuePair<int, string> selected in Selected)
{
Available.Remove(selected.Key);
}
lbAvailable.Items.Refresh();
lbSelected.Items.Refresh();
}
private void Add_Button_Click(object sender, RoutedEventArgs e)
{
if (lbAvailable.SelectedItem != null)
{
int key = ((KeyValuePair<int, string>)lbAvailable.SelectedItem).Key;
Keys.Add(key);
UpdateColumns();
}
}
private void Remove_Button_Click(object sender, RoutedEventArgs e)
{
if (lbSelected.SelectedItem != null)
{
int key = ((KeyValuePair<int, string>)lbSelected.SelectedItem).Key;
Keys.Remove(key);
UpdateColumns();
}
}
private void Save_Button_Click(object sender, RoutedEventArgs e)
{
if (txtName.Text.Length == 0)
{
MessageBox.Show("Group name required", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (txtName.Text != LocalGroup.Name)
{
foreach (Container.GroupItem groupItem in Settings.ContainerInner.Groups)
{
if (txtName.Text == groupItem.Name)
{
MessageBox.Show("Group name must be unique", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
}
LocalGroup.Name = txtName.Text;
LocalGroup.Keys.Clear();
LocalGroup.Keys.AddRange(Keys);
}
}
}

View File

@ -0,0 +1,48 @@
<UserControl x:Class="KFDtool.Gui.Dialog.ContainerEditKeyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:KFDtool.Gui.Dialog"
mc:Ignorable="d"
d:DesignHeight="325" d:DesignWidth="685">
<Grid>
<Label Content="Name" HorizontalAlignment="Left" Margin="10,24,0,0" VerticalAlignment="Top"/>
<TextBox Name="txtName" HorizontalAlignment="Left" Height="23" Margin="85,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="258"/>
<Label Content="Dec" HorizontalContentAlignment="Center" HorizontalAlignment="Left" Margin="85,52,0,0" VerticalAlignment="Top" Width="120"/>
<Label Content="Hex" HorizontalContentAlignment="Center" HorizontalAlignment="Left" Margin="223,52,0,0" VerticalAlignment="Top" Width="120"/>
<Label Content="Keyset ID" HorizontalAlignment="Left" Margin="10,80,0,0" VerticalAlignment="Top"/>
<TextBox Name="txtKeysetIdDec" TextChanged="KeysetIdDec_TextChanged" HorizontalAlignment="Left" Height="23" Margin="85,83,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox Name="txtKeysetIdHex" TextChanged="KeysetIdHex_TextChanged" HorizontalAlignment="Left" Height="23" Margin="223,83,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<CheckBox Name="cbActiveKeyset" Content="Active Keyset" Checked="OnActiveKeysetChecked" Unchecked="OnActiveKeysetUnchecked" HorizontalAlignment="Left" Margin="359,87,0,0" VerticalAlignment="Top"/>
<Label Content="SLN/CKR" HorizontalAlignment="Left" Margin="10,114,0,0" VerticalAlignment="Top"/>
<TextBox Name="txtSlnDec" TextChanged="SlnDec_TextChanged" HorizontalAlignment="Left" Height="23" Margin="85,117,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox Name="txtSlnHex" TextChanged="SlnHex_TextChanged" HorizontalAlignment="Left" Height="23" Margin="223,117,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label Content="Key Type" HorizontalAlignment="Left" Margin="10,147,0,0" VerticalAlignment="Top"/>
<ComboBox Name="cboType" SelectionChanged="OnTypeChanged" HorizontalAlignment="Left" Margin="85,151,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Name="AUTO" Content="Auto" />
<ComboBoxItem Name="TEK" Content="TEK" />
<ComboBoxItem Name="KEK" Content="KEK" />
</ComboBox>
<Label Name="lblType" Content="Label" HorizontalContentAlignment="Center" HorizontalAlignment="Left" Margin="223,147,0,0" VerticalAlignment="Top" Width="120"/>
<Label Content="Key ID" HorizontalAlignment="Left" Margin="10,181,0,0" VerticalAlignment="Top"/>
<TextBox Name="txtKeyIdDec" TextChanged="KeyIdDec_TextChanged" HorizontalAlignment="Left" Height="23" Margin="85,184,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox Name="txtKeyIdHex" TextChanged="KeyIdHex_TextChanged" HorizontalAlignment="Left" Height="23" Margin="223,184,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label Content="Algorithm" HorizontalAlignment="Left" Margin="10,215,0,0" VerticalAlignment="Top"/>
<TextBox Name="txtAlgoDec" TextChanged="AlgoDec_TextChanged" HorizontalAlignment="Left" Height="23" Margin="85,218,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox Name="txtAlgoHex" TextChanged="AlgoHex_TextChanged" HorizontalAlignment="Left" Height="23" Margin="223,218,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<ComboBox Name="cboAlgo" SelectionChanged="OnAlgoChanged" HorizontalAlignment="Left" Margin="359,219,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Name="AES256" Content="AES-256" />
<ComboBoxItem Name="DESOFB" Content="DES-OFB" />
<ComboBoxItem Name="DESXL" Content="DES-XL" />
<ComboBoxItem Name="ADP" Content="ADP/RC4" />
<ComboBoxItem Name="OTHER" Content="Other" />
</ComboBox>
<Label Content="Key (hex)" HorizontalAlignment="Left" Margin="10,249,0,0" VerticalAlignment="Top"/>
<PasswordBox Name="txtKeyHidden" HorizontalAlignment="Left" Height="23" Margin="85,252,0,0" VerticalAlignment="Top" Width="500"/>
<TextBox Name="txtKeyVisible" HorizontalAlignment="Left" Height="23" Margin="85,252,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="500"/>
<Button Content="Generate" Click="Generate_Button_Click" HorizontalAlignment="Left" Margin="602,255,0,0" VerticalAlignment="Top" Width="75"/>
<CheckBox Name="cbHide" Content="Hide" Checked="OnHideChecked" Unchecked="OnHideUnchecked" HorizontalAlignment="Left" Margin="540,288,0,0" VerticalAlignment="Top"/>
<Button Content="Save" Click="Save_Button_Click" HorizontalAlignment="Left" Margin="85,288,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,605 @@
using KFDtool.Container;
using KFDtool.P25.Constant;
using KFDtool.P25.Generator;
using KFDtool.P25.Validator;
using KFDtool.Shared;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
namespace KFDtool.Gui.Dialog
{
/// <summary>
/// Interaction logic for ContainerEditKeyControl.xaml
/// </summary>
public partial class ContainerEditKeyControl : UserControl
{
private KeyItem LocalKey { get; set; }
private bool IsKek { get; set; }
public ContainerEditKeyControl(KeyItem keyItem)
{
InitializeComponent();
LocalKey = keyItem;
txtName.Text = keyItem.Name;
if (keyItem.ActiveKeyset)
{
cbActiveKeyset.IsChecked = true;
}
else
{
cbActiveKeyset.IsChecked = false;
txtKeysetIdDec.Text = keyItem.KeysetId.ToString();
UpdateKeysetIdDec();
}
if (keyItem.KeyTypeAuto)
{
cboType.SelectedIndex = 0;
}
else if (keyItem.KeyTypeTek)
{
cboType.SelectedIndex = 1;
}
else if (keyItem.KeyTypeKek)
{
cboType.SelectedIndex = 2;
}
else
{
throw new Exception("invalid key type");
}
txtSlnDec.Text = keyItem.Sln.ToString();
UpdateSlnDec();
txtKeyIdDec.Text = keyItem.KeyId.ToString();
UpdateKeyIdDec();
if (keyItem.AlgorithmId == 0x84)
{
cboAlgo.SelectedIndex = 0;
}
else if (keyItem.AlgorithmId == 0x81)
{
cboAlgo.SelectedIndex = 1;
}
else if (keyItem.AlgorithmId == 0x9F)
{
cboAlgo.SelectedIndex = 2;
}
else if (keyItem.AlgorithmId == 0xAA)
{
cboAlgo.SelectedIndex = 3;
}
else
{
cboAlgo.SelectedIndex = 4;
txtAlgoDec.Text = keyItem.AlgorithmId.ToString();
UpdateAlgoDec();
}
cbHide.IsChecked = true;
txtKeyHidden.Password = keyItem.Key;
}
private void UpdateKeysetIdDec()
{
int num;
if (int.TryParse(txtKeysetIdDec.Text, out num))
{
txtKeysetIdHex.Text = string.Format("{0:X}", num);
}
else
{
txtKeysetIdHex.Text = string.Empty;
}
}
private void UpdateKeysetIdHex()
{
int num;
if (int.TryParse(txtKeysetIdHex.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num))
{
txtKeysetIdDec.Text = num.ToString();
}
else
{
txtKeysetIdDec.Text = string.Empty;
}
}
private void KeysetIdDec_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtKeysetIdDec.IsFocused)
{
UpdateKeysetIdDec();
}
}
private void KeysetIdHex_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtKeysetIdHex.IsFocused)
{
UpdateKeysetIdHex();
}
}
private void OnActiveKeysetChecked(object sender, RoutedEventArgs e)
{
txtKeysetIdDec.Text = string.Empty;
txtKeysetIdHex.Text = string.Empty;
txtKeysetIdDec.IsEnabled = false;
txtKeysetIdHex.IsEnabled = false;
}
private void OnActiveKeysetUnchecked(object sender, RoutedEventArgs e)
{
txtKeysetIdDec.IsEnabled = true;
txtKeysetIdHex.IsEnabled = true;
}
private void UpdateSlnDec()
{
int num;
if (int.TryParse(txtSlnDec.Text, out num))
{
txtSlnHex.Text = string.Format("{0:X}", num);
}
else
{
txtSlnHex.Text = string.Empty;
}
UpdateType();
}
private void UpdateSlnHex()
{
int num;
if (int.TryParse(txtSlnHex.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num))
{
txtSlnDec.Text = num.ToString();
}
else
{
txtSlnDec.Text = string.Empty;
}
UpdateType();
}
private void SlnDec_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtSlnDec.IsFocused)
{
UpdateSlnDec();
}
}
private void SlnHex_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtSlnHex.IsFocused)
{
UpdateSlnHex();
}
}
private void UpdateType()
{
if (cboType.SelectedItem != null)
{
string name = ((ComboBoxItem)cboType.SelectedItem).Name as string;
if (name == "AUTO")
{
int num;
if (int.TryParse(txtSlnHex.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num))
{
if (num >= 0 && num <= 61439)
{
lblType.Content = "TEK";
IsKek = false;
}
else if (num >= 61440 && num <= 65535)
{
lblType.Content = "KEK";
IsKek = true;
}
else
{
lblType.Content = "Auto";
}
}
else
{
lblType.Content = "Auto";
}
}
else if (name == "TEK")
{
lblType.Content = "TEK";
IsKek = false;
}
else if (name == "KEK")
{
lblType.Content = "KEK";
IsKek = true;
}
else
{
// error
}
}
}
private void OnTypeChanged(object sender, SelectionChangedEventArgs e)
{
UpdateType();
}
private void UpdateKeyIdDec()
{
int num;
if (int.TryParse(txtKeyIdDec.Text, out num))
{
txtKeyIdHex.Text = string.Format("{0:X}", num);
}
else
{
txtKeyIdHex.Text = string.Empty;
}
}
private void UpdateKeyIdHex()
{
int num;
if (int.TryParse(txtKeyIdHex.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num))
{
txtKeyIdDec.Text = num.ToString();
}
else
{
txtKeyIdDec.Text = string.Empty;
}
}
private void KeyIdDec_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtKeyIdDec.IsFocused)
{
UpdateKeyIdDec();
}
}
private void KeyIdHex_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtKeyIdHex.IsFocused)
{
UpdateKeyIdHex();
}
}
private void UpdateAlgoDec()
{
int num;
if (int.TryParse(txtAlgoDec.Text, out num))
{
txtAlgoHex.Text = string.Format("{0:X}", num);
}
else
{
txtAlgoHex.Text = string.Empty;
}
}
private void UpdateAlgoHex()
{
int num;
if (int.TryParse(txtAlgoHex.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num))
{
txtAlgoDec.Text = num.ToString();
}
else
{
txtAlgoDec.Text = string.Empty;
}
}
private void AlgoDec_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtAlgoDec.IsFocused)
{
UpdateAlgoDec();
}
}
private void AlgoHex_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtAlgoHex.IsFocused)
{
UpdateAlgoHex();
}
}
private void OnAlgoChanged(object sender, SelectionChangedEventArgs e)
{
if (cboAlgo.SelectedItem != null)
{
string name = ((ComboBoxItem)cboAlgo.SelectedItem).Name as string;
if (name == "AES256")
{
txtAlgoHex.Text = "84";
UpdateAlgoHex();
txtAlgoDec.IsEnabled = false;
txtAlgoHex.IsEnabled = false;
}
else if (name == "DESOFB")
{
txtAlgoHex.Text = "81";
UpdateAlgoHex();
txtAlgoDec.IsEnabled = false;
txtAlgoHex.IsEnabled = false;
}
else if (name == "DESXL")
{
txtAlgoHex.Text = "9F";
UpdateAlgoHex();
txtAlgoDec.IsEnabled = false;
txtAlgoHex.IsEnabled = false;
}
else if (name == "ADP")
{
txtAlgoHex.Text = "AA";
UpdateAlgoHex();
txtAlgoDec.IsEnabled = false;
txtAlgoHex.IsEnabled = false;
}
else
{
txtAlgoDec.Text = string.Empty;
txtAlgoHex.Text = string.Empty;
txtAlgoDec.IsEnabled = true;
txtAlgoHex.IsEnabled = true;
}
}
}
private void Generate_Button_Click(object sender, RoutedEventArgs e)
{
int algId = 0;
try
{
algId = Convert.ToInt32(txtAlgoHex.Text, 16);
}
catch (Exception)
{
MessageBox.Show("Error Parsing Algorithm ID", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (!FieldValidator.IsValidAlgorithmId(algId))
{
MessageBox.Show("Algorithm ID invalid - valid range 0 to 255 (dec), 0x00 to 0xFF (hex)", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
List<byte> key = new List<byte>();
if (algId == (byte)AlgorithmId.AES256)
{
key = KeyGenerator.GenerateVarKey(32);
}
else if (algId == (byte)AlgorithmId.DESOFB || algId == (byte)AlgorithmId.DESXL)
{
key = KeyGenerator.GenerateSingleDesKey();
}
else if (algId == (byte)AlgorithmId.ADP)
{
key = KeyGenerator.GenerateVarKey(5);
}
else
{
MessageBox.Show(string.Format("No key generator exists for algorithm ID 0x{0:X2}", algId), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
SetKey(BitConverter.ToString(key.ToArray()).Replace("-", string.Empty));
}
private void OnHideChecked(object sender, RoutedEventArgs e)
{
txtKeyHidden.Password = txtKeyVisible.Text;
txtKeyVisible.Text = string.Empty;
txtKeyVisible.Visibility = Visibility.Hidden;
txtKeyHidden.Visibility = Visibility.Visible;
}
private void OnHideUnchecked(object sender, RoutedEventArgs e)
{
txtKeyVisible.Text = txtKeyHidden.Password;
txtKeyHidden.Password = null;
txtKeyVisible.Visibility = Visibility.Visible;
txtKeyHidden.Visibility = Visibility.Hidden;
}
private string GetKey()
{
if (cbHide.IsChecked == true)
{
return txtKeyHidden.Password;
}
else
{
return txtKeyVisible.Text;
}
}
private void SetKey(string str)
{
if (cbHide.IsChecked == true)
{
txtKeyHidden.Password = str;
}
else
{
txtKeyVisible.Text = str;
}
}
private void Save_Button_Click(object sender, RoutedEventArgs e)
{
int keysetId;
int sln;
int keyId;
int algId;
List<byte> key;
bool useActiveKeyset = cbActiveKeyset.IsChecked == true;
if (useActiveKeyset)
{
keysetId = 1; // to pass validation, will not get used
}
else
{
try
{
keysetId = Convert.ToInt32(txtKeysetIdHex.Text, 16);
}
catch (Exception)
{
MessageBox.Show("Error Parsing Keyset ID", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
try
{
sln = Convert.ToInt32(txtSlnHex.Text, 16);
}
catch (Exception)
{
MessageBox.Show("Error Parsing SLN", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
try
{
keyId = Convert.ToInt32(txtKeyIdHex.Text, 16);
}
catch (Exception)
{
MessageBox.Show("Error Parsing Key ID", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
try
{
algId = Convert.ToInt32(txtAlgoHex.Text, 16);
}
catch (Exception)
{
MessageBox.Show("Error Parsing Algorithm ID", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
try
{
key = Utility.ByteStringToByteList(GetKey());
}
catch (Exception)
{
MessageBox.Show("Error Parsing Key", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
Tuple<ValidateResult, string> validateResult = FieldValidator.KeyloadValidate(keysetId, sln, IsKek, keyId, algId, key);
if (validateResult.Item1 == ValidateResult.Warning)
{
if (MessageBox.Show(string.Format("{1}{0}{0}Continue?", Environment.NewLine, validateResult.Item2), "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.No)
{
return;
}
}
else if (validateResult.Item1 == ValidateResult.Error)
{
MessageBox.Show(validateResult.Item2, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (txtName.Text.Length == 0)
{
MessageBox.Show("Key name required", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (txtName.Text != LocalKey.Name)
{
foreach (KeyItem keyItem in Settings.ContainerInner.Keys)
{
if (txtName.Text == keyItem.Name)
{
MessageBox.Show("Key name must be unique", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
}
LocalKey.Name = txtName.Text;
LocalKey.ActiveKeyset = useActiveKeyset;
LocalKey.KeysetId = keysetId;
LocalKey.Sln = sln;
if (cboType.SelectedIndex == 0)
{
LocalKey.KeyTypeAuto = true;
LocalKey.KeyTypeTek = false;
LocalKey.KeyTypeKek = false;
}
else if (cboType.SelectedIndex == 1)
{
LocalKey.KeyTypeAuto = false;
LocalKey.KeyTypeTek = true;
LocalKey.KeyTypeKek = false;
}
else if (cboType.SelectedIndex == 2)
{
LocalKey.KeyTypeAuto = false;
LocalKey.KeyTypeTek = false;
LocalKey.KeyTypeKek = true;
}
else
{
throw new Exception("invalid key type");
}
LocalKey.KeyId = keyId;
LocalKey.AlgorithmId = algId;
LocalKey.Key = BitConverter.ToString(key.ToArray()).Replace("-", string.Empty);
}
}
}

View File

@ -0,0 +1,14 @@
<Window x:Class="KFDtool.Gui.Dialog.ContainerEnterPassword"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:KFDtool.Gui.Dialog"
mc:Ignorable="d"
Title="Enter Container Password" Height="120" Width="350" WindowStartupLocation="CenterOwner" ResizeMode="NoResize">
<Grid>
<Label Content="Password" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<PasswordBox Name="txtPassword" HorizontalAlignment="Left" Margin="75,15,0,0" VerticalAlignment="Top" Width="250"/>
<Button Content="Submit" Click="Submit_Click" IsDefault="True" HorizontalAlignment="Left" Margin="75,44,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>

View File

@ -0,0 +1,38 @@
using System.Windows;
namespace KFDtool.Gui.Dialog
{
/// <summary>
/// Interaction logic for ContainerEnterPassword.xaml
/// </summary>
public partial class ContainerEnterPassword : Window
{
public bool PasswordSet { get; set; }
public string PasswordText { get; set; }
public ContainerEnterPassword()
{
InitializeComponent();
PasswordSet = false;
PasswordText = string.Empty;
txtPassword.Focus(); // focus first password field on load
}
private void Submit_Click(object sender, RoutedEventArgs e)
{
if (txtPassword.Password.Length == 0)
{
MessageBox.Show("Password is required", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
PasswordSet = true;
PasswordText = txtPassword.Password;
Close();
}
}
}

View File

@ -0,0 +1,16 @@
<Window x:Class="KFDtool.Gui.Dialog.ContainerSetPassword"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:KFDtool.Gui.Dialog"
mc:Ignorable="d"
Title="Set Container Password" Height="150" Width="400" WindowStartupLocation="CenterOwner" ResizeMode="NoResize">
<Grid>
<Label Content="Password" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<PasswordBox Name="txtPassword" HorizontalAlignment="Left" Margin="120,15,0,0" VerticalAlignment="Top" Width="250"/>
<Label Content="Confirm Password" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
<PasswordBox Name="txtPasswordConfirm" HorizontalAlignment="Left" Margin="120,46,0,0" VerticalAlignment="Top" Width="250"/>
<Button Content="Set Password" Click="Set_Password_Click" IsDefault="True" HorizontalAlignment="Left" Margin="120,76,0,0" VerticalAlignment="Top" Width="100"/>
</Grid>
</Window>

View File

@ -0,0 +1,54 @@
using System.Windows;
namespace KFDtool.Gui.Dialog
{
/// <summary>
/// Interaction logic for ContainerSetPassword.xaml
/// </summary>
public partial class ContainerSetPassword : Window
{
public bool PasswordSet { get; set; }
public string PasswordText { get; set; }
public ContainerSetPassword()
{
InitializeComponent();
PasswordSet = false;
PasswordText = string.Empty;
txtPassword.Focus(); // focus first password field on load
}
private void Set_Password_Click(object sender, RoutedEventArgs e)
{
if (txtPassword.Password != txtPasswordConfirm.Password)
{
MessageBox.Show("Passwords do not match", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (txtPassword.Password.Length == 0)
{
MessageBox.Show("Password is required", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (txtPassword.Password.Length < 16)
{
MessageBoxResult res = MessageBox.Show("This password is weak (under 16 characters in length) - use anyways?", "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (res == MessageBoxResult.No)
{
return;
}
}
PasswordSet = true;
PasswordText = txtPassword.Password;
Close();
}
}
}

View File

@ -44,7 +44,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.1\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.7.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@ -80,6 +80,9 @@
<Compile Include="Control\P25MrEmulator.xaml.cs">
<DependentUpon>P25MrEmulator.xaml</DependentUpon>
</Compile>
<Compile Include="Control\P25MultipleKeyload.xaml.cs">
<DependentUpon>P25MultipleKeyload.xaml</DependentUpon>
</Compile>
<Compile Include="Control\P25ViewKeyInfo.xaml.cs">
<DependentUpon>P25ViewKeyInfo.xaml</DependentUpon>
</Compile>
@ -104,6 +107,21 @@
<Compile Include="Control\UtilUpdateAdapterFw.xaml.cs">
<DependentUpon>UtilUpdateAdapterFw.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\ContainerEdit.xaml.cs">
<DependentUpon>ContainerEdit.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\ContainerEditGroupControl.xaml.cs">
<DependentUpon>ContainerEditGroupControl.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\ContainerEditKeyControl.xaml.cs">
<DependentUpon>ContainerEditKeyControl.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\ContainerEnterPassword.xaml.cs">
<DependentUpon>ContainerEnterPassword.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\ContainerSetPassword.xaml.cs">
<DependentUpon>ContainerSetPassword.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\DliIpDeviceEdit.xaml.cs">
<DependentUpon>DliIpDeviceEdit.xaml</DependentUpon>
</Compile>
@ -121,6 +139,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Control\P25MultipleKeyload.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Control\P25ViewKeyInfo.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -157,6 +179,26 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\ContainerEdit.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\ContainerEditGroupControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\ContainerEditKeyControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\ContainerEnterPassword.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\ContainerSetPassword.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\DliIpDeviceEdit.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -199,9 +241,6 @@
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="NLog.xsd">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
@ -219,6 +258,10 @@
<Project>{a13f6741-6c04-4c9f-affc-a0b7e0d25762}</Project>
<Name>KFDtool.Adapter</Name>
</ProjectReference>
<ProjectReference Include="..\KFDtool.Container\KFDtool.Container.csproj">
<Project>{4e99ec83-6ee7-49e0-a9af-6674a53f578c}</Project>
<Name>KFDtool.Container</Name>
</ProjectReference>
<ProjectReference Include="..\KFDtool.P25\KFDtool.P25.csproj">
<Project>{824aca5b-01db-42b7-892f-e4cec6ff3887}</Project>
<Name>KFDtool.P25</Name>

View File

@ -5,19 +5,29 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:KFDtool.Gui"
mc:Ignorable="d"
Height="450" Width="800" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" Closing="MainWindow_Closing">
Height="485" Width="800" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" Closing="MainWindow_Closing">
<Grid>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Exit" Click="Exit_MenuItem_Click" />
</MenuItem>
<MenuItem Name="ContainerMenu" Header="_Container">
<MenuItem Name="miContainerNew" Header="_New" Click="Container_New_Click" />
<MenuItem Name="miContainerOpen" Header="_Open" Click="Container_Open_Click" />
<MenuItem Header="_Edit" Click="Container_Edit_Click" />
<MenuItem Header="_Change Password" Click="Container_Change_Password_Click" />
<MenuItem Header="_Save" Click="Container_Save_Click"/>
<MenuItem Header="_Save As" Click="Container_Save_As_Click"/>
<MenuItem Header="_Close" Click="Container_Close_Click"/>
</MenuItem>
<MenuItem Name="TypeMenu" Header="_Type">
<MenuItem Name="TypeTwiKfdtool" Header="_TWI (KFDtool)" Click="Type_MenuItem_Click" />
<MenuItem Name="TypeDliIp" Header="_DLI (IP)" Click="Type_MenuItem_Click" />
</MenuItem>
<MenuItem Name="DeviceMenu" Header="_Device" />
<MenuItem Name="P25KfdMenu" Header="_P25 KFD">
<MenuItem Name="NavigateP25MultipleKeyload" Header="_Multiple Keyload" IsCheckable="True" Click="Navigate_MenuItem_Click" />
<MenuItem Name="NavigateP25Keyload" Header="_Keyload" IsCheckable="True" Click="Navigate_MenuItem_Click" />
<MenuItem Name="NavigateP25KeyErase" Header="_Key Erase" IsCheckable="True" Click="Navigate_MenuItem_Click" />
<MenuItem Name="NavigateP25EraseAllKeys" Header="_Erase All Keys" IsCheckable="True" Click="Navigate_MenuItem_Click" />
@ -42,9 +52,14 @@
</MenuItem>
</Menu>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem>
<TextBlock Name="lblSelectedDevice"></TextBlock>
</StatusBarItem>
<StackPanel Orientation="Vertical">
<StatusBarItem>
<TextBlock Name="lblSelectedContainer"></TextBlock>
</StatusBarItem>
<StatusBarItem>
<TextBlock Name="lblSelectedDevice"></TextBlock>
</StatusBarItem>
</StackPanel>
</StatusBar>
<Grid >
<ContentControl Name="AppView"/>

View File

@ -1,22 +1,16 @@
using KFDtool.Adapter.Device;
using KFDtool.Container;
using KFDtool.Gui.Dialog;
using KFDtool.P25.TransferConstructs;
using Microsoft.Win32;
using NLog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace KFDtool.Gui
{
@ -25,7 +19,7 @@ namespace KFDtool.Gui
/// </summary>
public partial class MainWindow : Window
{
private static NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private static Logger Log = LogManager.GetCurrentClassLogger();
private AutoDetection AppDet;
@ -33,7 +27,7 @@ namespace KFDtool.Gui
{
InitializeComponent();
Logger.Info("starting");
UpdateContainerText();
InitAppDet();
@ -41,24 +35,63 @@ namespace KFDtool.Gui
SwitchType(TypeTwiKfdtool);
// on load select the P25 Keyload function
SwitchScreen(NavigateP25Keyload);
SwitchScreen("NavigateP25Keyload", true);
}
void MainWindow_Closing(object sender, CancelEventArgs e)
{
if (Settings.InProgressScreen != string.Empty)
// prevent exit if operation is in progress
if (Settings.ScreenInProgress)
{
UpdateSelectionOnly(Settings.InProgressScreen);
SwitchScreen(Settings.ScreenCurrent, false);
MessageBox.Show("Unable to exit - please stop the current operation", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
e.Cancel = true;
}
Logger.Info("stopping");
// ask user if container should be saved before exiting
if (Settings.ContainerOpen)
{
if (!Settings.ContainerSaved)
{
MessageBoxResult res = MessageBox.Show("Container is unsaved - save before closing?", "Warning", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);
if (res == MessageBoxResult.Yes)
{
ContainerSave();
ContainerClose();
}
else if (res == MessageBoxResult.Cancel)
{
e.Cancel = true;
return;
}
}
}
// have to stop the WMI watcher or a RCW exception will be thrown
StopAppDet();
}
#region navigate
private void ClearAllSelections()
{
foreach (MenuItem item in P25KfdMenu.Items)
{
item.IsChecked = false;
}
foreach (MenuItem item in P25MrMenu.Items)
{
item.IsChecked = false;
}
foreach (MenuItem item in UtilityMenu.Items)
{
item.IsChecked = false;
}
}
private void UpdateTitle(string s)
{
#if DEBUG
@ -68,6 +101,425 @@ namespace KFDtool.Gui
#endif
}
private void SwitchScreen(string item, bool changeControl)
{
ClearAllSelections();
object control;
if (item == "NavigateP25MultipleKeyload")
{
control = new Control.P25MultipleKeyload();
NavigateP25MultipleKeyload.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - Multiple Keyload");
}
else if (item == "NavigateP25Keyload")
{
control = new Control.P25Keyload();
NavigateP25Keyload.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - Keyload");
}
else if (item == "NavigateP25KeyErase")
{
control = new Control.P25KeyErase();
NavigateP25KeyErase.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - Key Erase");
}
else if (item == "NavigateP25EraseAllKeys")
{
control = new Control.P25EraseAllKeys();
NavigateP25EraseAllKeys.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - Erase All Keys");
}
else if (item == "NavigateP25ViewKeyInfo")
{
control = new Control.P25ViewKeyInfo();
NavigateP25ViewKeyInfo.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - View Key Info");
}
else if (item == "NavigateP25ViewKeysetInfo")
{
control = new Control.P25ViewKeysetInfo();
NavigateP25ViewKeysetInfo.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - View Keyset Info");
}
else if (item == "NavigateP25ViewRsiConfig")
{
control = new Control.P25ViewRsiConfig();
NavigateP25ViewRsiConfig.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - RSI Configuration");
}
else if (item == "NavigateP25KmfConfig")
{
control = new Control.P25KmfConfig();
NavigateP25KmfConfig.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 KFD - KMF Configuration");
}
else if (item == "NavigateP25MrEmulator")
{
control = new Control.P25MrEmulator();
NavigateP25MrEmulator.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("P25 MR - Emulator");
}
else if (item == "NavigateUtilityFixDesKeyParity")
{
control = new Control.UtilFixDesKeyParity();
NavigateUtilityFixDesKeyParity.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("Utility - Fix DES Key Parity");
}
else if (item == "NavigateUtilityUpdateAdapterFirmware")
{
control = new Control.UtilUpdateAdapterFw();
NavigateUtilityUpdateAdapterFirmware.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("Utility - Update Adapter Firmware");
}
else if (item == "NavigateUtilityInitializeAdapter")
{
control = new Control.UtilInitAdapter();
NavigateUtilityInitializeAdapter.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("Utility - Initialize Adapter");
}
else if (item == "NavigateUtilityAdapterSelfTest")
{
control = new Control.UtilAdapterSelfTest();
NavigateUtilityAdapterSelfTest.IsChecked = true;
Settings.ScreenCurrent = item;
UpdateTitle("Utility - Adapter Self Test");
}
else
{
throw new Exception(string.Format("unknown item passed to SwitchScreen - {0}", item));
}
if (changeControl)
{
AppView.Content = control;
}
}
private void Navigate_MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
if (Settings.ScreenInProgress)
{
SwitchScreen(Settings.ScreenCurrent, false);
MessageBox.Show("Unable to change screens - please stop the current operation", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
else if (!Settings.ContainerOpen && mi.Name == "NavigateP25MultipleKeyload")
{
SwitchScreen(Settings.ScreenCurrent, false);
MessageBox.Show("No container open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
else
{
SwitchScreen(mi.Name, true);
}
}
}
#endregion
#region container
public void UpdateContainerText()
{
if (Settings.ContainerOpen)
{
lblSelectedContainer.Text = string.Format("Selected Container: {0}{1}", Settings.ContainerSaved ? string.Empty : "[UNSAVED] ", Settings.ContainerPath);
}
else
{
lblSelectedContainer.Text = "Selected Container: None";
}
}
private void Container_New_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
MessageBox.Show("A container is already open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
ContainerSetPassword containerSetPassword = new ContainerSetPassword();
containerSetPassword.Owner = this; // for centering in parent window
containerSetPassword.ShowDialog();
if (containerSetPassword.PasswordSet)
{
string password = containerSetPassword.PasswordText;
Settings.ContainerOpen = true;
Settings.ContainerSaved = false;
Settings.ContainerPath = string.Empty;
(Settings.ContainerOuter, Settings.ContainerKey) = ContainerUtilities.CreateOuterContainer(password);
Settings.ContainerInner = ContainerUtilities.CreateInnerContainer();
UpdateContainerText();
}
}
private void Container_Open_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
MessageBox.Show("A container is already open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Encrypted Key Container (*.ekc)|*.ekc|All files (*.*)|*.*";
if (openFileDialog.ShowDialog() == true)
{
string filePath = openFileDialog.FileName;
if (filePath.Equals(string.Empty))
{
MessageBox.Show("No file selected", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
ContainerEnterPassword containerEnterPassword = new ContainerEnterPassword();
containerEnterPassword.Owner = this; // for centering in parent window
containerEnterPassword.ShowDialog();
if (containerEnterPassword.PasswordSet)
{
string password = containerEnterPassword.PasswordText;
byte[] fileContents;
try
{
fileContents = File.ReadAllBytes(filePath);
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to read file: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
OuterContainer outerContainer;
InnerContainer innerContainer;
byte[] key;
try
{
(outerContainer, innerContainer, key) = ContainerUtilities.DecryptOuterContainer(fileContents, password);
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to decrypt container: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
Settings.ContainerOpen = true;
Settings.ContainerSaved = true;
Settings.ContainerPath = filePath;
Settings.ContainerKey = key;
Settings.ContainerOuter = outerContainer;
Settings.ContainerInner = innerContainer;
UpdateContainerText();
}
}
}
private void Container_Edit_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
ContainerEdit containerEdit = new ContainerEdit();
containerEdit.Owner = this; // for centering in parent window
try
{
containerEdit.ShowDialog();
}
catch (Exception ex)
{
containerEdit.Close();
MessageBox.Show(string.Format("Error modifying key container - {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
ContainerClose();
return;
}
UpdateContainerText();
if (!Settings.ContainerSaved && Settings.ScreenCurrent == "NavigateP25MultipleKeyload")
{
SwitchScreen(Settings.ScreenCurrent, true);
MessageBox.Show("Multiple keyload selections reset due to key container edit", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
else
{
MessageBox.Show("No container open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void Container_Change_Password_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
ContainerSetPassword containerSetPassword = new ContainerSetPassword();
containerSetPassword.Owner = this; // for centering in parent window
containerSetPassword.ShowDialog();
if (containerSetPassword.PasswordSet)
{
string password = containerSetPassword.PasswordText;
(Settings.ContainerOuter, Settings.ContainerKey) = ContainerUtilities.CreateOuterContainer(password);
Settings.ContainerSaved = false;
UpdateContainerText();
MessageBox.Show("Password Changed", "Information", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
else
{
MessageBox.Show("No container open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void ContainerWrite(string path)
{
byte[] contents;
try
{
contents = ContainerUtilities.EncryptOuterContainer(Settings.ContainerOuter, Settings.ContainerInner, Settings.ContainerKey);
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to encrypt container: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
try
{
File.WriteAllBytes(path, contents);
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to write file: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
Settings.ContainerPath = path;
Settings.ContainerSaved = true;
UpdateContainerText();
}
private void ContainerSaveAs()
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "Encrypted Key Container (*.ekc)|*.ekc";
if (saveFileDialog.ShowDialog() == true)
{
ContainerWrite(saveFileDialog.FileName);
}
}
private void ContainerSave()
{
if (Settings.ContainerPath != string.Empty)
{
ContainerWrite(Settings.ContainerPath);
}
else
{
ContainerSaveAs();
}
}
private void Container_Save_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
ContainerSave();
}
else
{
MessageBox.Show("No container open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void Container_Save_As_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
ContainerSaveAs();
}
else
{
MessageBox.Show("No container open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void ContainerClose()
{
if (Settings.ScreenCurrent == "NavigateP25MultipleKeyload")
{
SwitchScreen("NavigateP25Keyload", true);
}
Settings.ContainerOpen = false;
Settings.ContainerSaved = false;
Settings.ContainerPath = string.Empty;
Settings.ContainerKey = null;
Settings.ContainerOuter = null;
Settings.ContainerInner = null;
UpdateContainerText();
}
private void Container_Close_Click(object sender, RoutedEventArgs e)
{
if (Settings.ContainerOpen)
{
if (!Settings.ContainerSaved)
{
MessageBoxResult res = MessageBox.Show("Container is unsaved - save before closing?", "Warning", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);
if (res == MessageBoxResult.Yes)
{
ContainerSave();
}
else if (res == MessageBoxResult.Cancel)
{
return;
}
}
ContainerClose();
}
else
{
MessageBox.Show("No container open", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
#endregion
private void SwitchType(MenuItem mi)
{
foreach (MenuItem item in TypeMenu.Items)
@ -130,130 +582,6 @@ namespace KFDtool.Gui
UpdateDeviceDliIp();
}
private void Navigate_MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
if (Settings.InProgressScreen != string.Empty)
{
UpdateSelectionOnly(Settings.InProgressScreen);
MessageBox.Show("Unable to change screens - please stop the current operation", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
else
{
SwitchScreen(mi);
}
}
}
private void ClearAllSelections()
{
foreach (MenuItem item in P25KfdMenu.Items)
{
item.IsChecked = false;
}
foreach (MenuItem item in P25MrMenu.Items)
{
item.IsChecked = false;
}
foreach (MenuItem item in UtilityMenu.Items)
{
item.IsChecked = false;
}
}
private void UpdateSelectionOnly(string item)
{
ClearAllSelections();
if (item == "NavigateP25MrEmulator")
{
NavigateP25MrEmulator.IsChecked = true;
}
else
{
Logger.Fatal("unknown item passed to UpdateSelectionOnly - {0}", item);
Application.Current.Shutdown(1);
}
}
private void SwitchScreen(MenuItem mi)
{
ClearAllSelections();
mi.IsChecked = true;
if (mi.Name == "NavigateP25Keyload")
{
AppView.Content = new Control.P25Keyload();
UpdateTitle("P25 KFD - Keyload");
}
else if (mi.Name == "NavigateP25KeyErase")
{
AppView.Content = new Control.P25KeyErase();
UpdateTitle("P25 KFD - Key Erase");
}
else if (mi.Name == "NavigateP25EraseAllKeys")
{
AppView.Content = new Control.P25EraseAllKeys();
UpdateTitle("P25 KFD - Erase All Keys");
}
else if (mi.Name == "NavigateP25ViewKeyInfo")
{
AppView.Content = new Control.P25ViewKeyInfo();
UpdateTitle("P25 KFD - View Key Info");
}
else if (mi.Name == "NavigateP25ViewKeysetInfo")
{
AppView.Content = new Control.P25ViewKeysetInfo();
UpdateTitle("P25 KFD - View Keyset Info");
}
else if (mi.Name == "NavigateP25ViewRsiConfig")
{
AppView.Content = new Control.P25ViewRsiConfig();
UpdateTitle("P25 KFD - RSI Configuration");
}
else if (mi.Name == "NavigateP25KmfConfig")
{
AppView.Content = new Control.P25KmfConfig();
UpdateTitle("P25 KFD - KMF Configuration");
}
else if (mi.Name == "NavigateP25MrEmulator")
{
AppView.Content = new Control.P25MrEmulator();
UpdateTitle("P25 MR - Emulator");
}
else if (mi.Name == "NavigateUtilityFixDesKeyParity")
{
AppView.Content = new Control.UtilFixDesKeyParity();
UpdateTitle("Utility - Fix DES Key Parity");
}
else if (mi.Name == "NavigateUtilityUpdateAdapterFirmware")
{
AppView.Content = new Control.UtilUpdateAdapterFw();
UpdateTitle("Utility - Update Adapter Firmware");
}
else if (mi.Name == "NavigateUtilityInitializeAdapter")
{
AppView.Content = new Control.UtilInitAdapter();
UpdateTitle("Utility - Initialize Adapter");
}
else if (mi.Name == "NavigateUtilityAdapterSelfTest")
{
AppView.Content = new Control.UtilAdapterSelfTest();
UpdateTitle("Utility - Adapter Self Test");
}
else
{
Logger.Fatal("unknown item passed to SwitchScreen - {0}", mi.Name);
Application.Current.Shutdown(1);
}
}
private void InitAppDet()
{
AppDet = new AutoDetection();
@ -272,7 +600,7 @@ namespace KFDtool.Gui
private void CheckConnectedDevices(object sender, EventArgs e)
{
Logger.Debug("device list updated");
Log.Debug("device list updated");
// needed to access UI elements from different thread
this.Dispatcher.Invoke(() =>

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,6 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]
[assembly: AssemblyInformationalVersion("1.5.0")]

View File

@ -1,11 +1,7 @@
using KFDtool.P25.TransferConstructs;
using System;
using System.Collections.Generic;
using KFDtool.Container;
using KFDtool.P25.TransferConstructs;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace KFDtool.Gui
{
@ -15,7 +11,21 @@ namespace KFDtool.Gui
public static string AssemblyInformationalVersion { get; private set; }
public static string InProgressScreen { get; set; }
public static string ScreenCurrent { get; set; }
public static bool ScreenInProgress { get; set; }
public static bool ContainerOpen { get; set; }
public static bool ContainerSaved { get; set; }
public static string ContainerPath { get; set; }
public static byte[] ContainerKey { get; set; }
public static OuterContainer ContainerOuter { get; set; }
public static InnerContainer ContainerInner { get; set; }
public static BaseDevice SelectedDevice { get; set; }
@ -23,7 +33,14 @@ namespace KFDtool.Gui
{
AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
AssemblyInformationalVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;
InProgressScreen = string.Empty;
ScreenCurrent = string.Empty;
ScreenInProgress = false;
ContainerOpen = false;
ContainerSaved = false;
ContainerPath = string.Empty;
ContainerKey = null;
ContainerInner = null;
ContainerOuter = null;
SelectedDevice = new BaseDevice();

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.1" targetFramework="net472" />
<package id="NLog.Schema" version="4.7.1" targetFramework="net472" />
<package id="NLog" version="4.7.3" targetFramework="net472" />
</packages>

View File

@ -34,7 +34,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.1\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.7.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />

View File

@ -41,7 +41,22 @@ namespace KFDtool.P25.Kmm
public override byte[] ToBytes()
{
throw new NotImplementedException();
List<byte> contents = new List<byte>();
/* inventory type */
contents.Add((byte)InventoryType);
/* number of items */
contents.Add((byte)((RsiItems.Count >> 8) & 0xFF));
contents.Add((byte)(RsiItems.Count & 0xFF));
/* items */
foreach (RsiItem item in RsiItems)
{
contents.AddRange(item.ToBytes());
}
return contents.ToArray();
}
public override void Parse(byte[] contents)

View File

@ -167,7 +167,17 @@ namespace KFDtool.P25.ManualRekey
{
string statusDescr = OperationStatusExtensions.ToStatusString((OperationStatus)status.Status);
string statusReason = OperationStatusExtensions.ToReasonString((OperationStatus)status.Status);
throw new Exception(string.Format("received unexpected key status{0}status: {1} (0x{2:X2}){0}{3}", Environment.NewLine, statusDescr, status.Status, statusReason));
throw new Exception(
string.Format(
"received unexpected key status{0}" +
"algorithm id: {1} (0x{1:X}){0}" +
"key id: {2} (0x{2:X}){0}" +
"status: {3} (0x{3:X}){0}" +
"status description: {4}{0}" +
"status reason: {5}",
Environment.NewLine, status.AlgorithmId, status.KeyId, status.Status, statusDescr, statusReason
)
);
}
}
}
@ -299,7 +309,17 @@ namespace KFDtool.P25.ManualRekey
{
string statusDescr = OperationStatusExtensions.ToStatusString((OperationStatus)status.Status);
string statusReason = OperationStatusExtensions.ToReasonString((OperationStatus)status.Status);
throw new Exception(string.Format("received unexpected key status{0}status: {1} (0x{2:X2}){0}{3}", Environment.NewLine, statusDescr, status.Status, statusReason));
throw new Exception(
string.Format(
"received unexpected key status{0}" +
"algorithm id: {1} (0x{1:X}){0}" +
"key id: {2} (0x{2:X}){0}" +
"status: {3} (0x{3:X}){0}" +
"status description: {4}{0}" +
"status reason: {5}",
Environment.NewLine, status.AlgorithmId, status.KeyId, status.Status, statusDescr, statusReason
)
);
}
}
}

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.1" targetFramework="net472" />
<package id="NLog" version="4.7.3" targetFramework="net472" />
</packages>

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyVersion("1.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]

View File

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Compression;
namespace KFDtool.Shared
{
@ -28,5 +27,45 @@ namespace KFDtool.Shared
{
return BitConverter.ToString(b.ToArray());
}
public static byte[] Compress(byte[] data)
{
byte[] buffer = data;
var memoryStream = new MemoryStream();
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gZipStream.Write(buffer, 0, buffer.Length);
}
memoryStream.Position = 0;
var compressedData = new byte[memoryStream.Length];
memoryStream.Read(compressedData, 0, compressedData.Length);
var gZipBuffer = new byte[compressedData.Length + 4];
Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
return gZipBuffer;
}
public static byte[] Decompress(byte[] data)
{
byte[] gZipBuffer = data;
using (var memoryStream = new MemoryStream())
{
int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4);
var buffer = new byte[dataLength];
memoryStream.Position = 0;
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
gZipStream.Read(buffer, 0, buffer.Length);
}
return buffer;
}
}
}
}

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.572
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KFDtool.Cmd", "KFDtool.Cmd\KFDtool.Cmd.csproj", "{46F51CF5-0A7F-4785-A4B1-E7EB8289FD24}"
EndProject
@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KFDtool.Shared", "KFDtool.S
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidLibrary", "HidLibrary\HidLibrary.csproj", "{12C7DCF8-287A-4CE9-A04D-ED8E037CD6AA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KFDtool.Container", "KFDtool.Container\KFDtool.Container.csproj", "{4E99EC83-6EE7-49E0-A9AF-6674A53F578C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -51,6 +53,10 @@ Global
{12C7DCF8-287A-4CE9-A04D-ED8E037CD6AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12C7DCF8-287A-4CE9-A04D-ED8E037CD6AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12C7DCF8-287A-4CE9-A04D-ED8E037CD6AA}.Release|Any CPU.Build.0 = Release|Any CPU
{4E99EC83-6EE7-49E0-A9AF-6674A53F578C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E99EC83-6EE7-49E0-A9AF-6674A53F578C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E99EC83-6EE7-49E0-A9AF-6674A53F578C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E99EC83-6EE7-49E0-A9AF-6674A53F578C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
<Product Id="*" UpgradeCode="{FD26DA57-FC28-486B-8E68-FABDB446C437}" Version="1.4.0" Language="1033" Name="KFDtool" Manufacturer="Daniel Dugger">
<Product Id="*" UpgradeCode="{FD26DA57-FC28-486B-8E68-FABDB446C437}" Version="1.5.0" Language="1033" Name="KFDtool" Manufacturer="Daniel Dugger">
<Package InstallerVersion="300" Compressed="yes" InstallScope="perMachine" />
<Media Id="1" Cabinet="KFDtool.cab" EmbedCab="yes" />