mirror of
https://gitlab.com/fabinfra/fabaccess/nfc.git
synced 2025-03-12 23:01:45 +01:00
182 lines
5.0 KiB
C#
182 lines
5.0 KiB
C#
using System;
|
|
|
|
namespace NFC.Helper.Crypto
|
|
{
|
|
/// <summary>
|
|
/// Key for DESFire Card
|
|
/// </summary>
|
|
public class CipherKey
|
|
{
|
|
#region Constructors
|
|
/// <summary>
|
|
/// Creates Key from Array
|
|
/// </summary>
|
|
/// <param name="key">Key</param>
|
|
/// <param name="cipher">Cipher for Key</param>
|
|
/// <param name="keyVersion">Version of Key</param>
|
|
public CipherKey(byte[] key, CipherType cipher, byte keyVersion)
|
|
{
|
|
_Cipher = cipher;
|
|
|
|
if (cipher == CipherType.AES && keyVersion < 0x10)
|
|
{
|
|
throw new ArgumentOutOfRangeException("KeyVersion is to low for AES Key (Minimum = 0x10)");
|
|
}
|
|
_KeyVersion = keyVersion;
|
|
|
|
if (!CheckKey(key, cipher))
|
|
{
|
|
throw new ArgumentException("Key is not vaild for CipherType");
|
|
}
|
|
|
|
if (cipher == CipherType.TDES || cipher == CipherType.TDES_2K || cipher == CipherType.TDES_3K)
|
|
{
|
|
_Key = SetKeyVersion(key, keyVersion);
|
|
}
|
|
else
|
|
{
|
|
_Key = key;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Key from String
|
|
/// </summary>
|
|
/// <param name="key">Key</param>
|
|
/// <param name="cipher">Cipher for Key</param>
|
|
/// <param name="keyVersion">Version of Key</param>
|
|
public CipherKey(string key, CipherType cipher, byte keyVersion) : this(HexConverter.ConvertFromHexString(key), cipher, keyVersion)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates Empty Key
|
|
/// </summary>
|
|
/// <param name="cipher">Cipher for Key</param>
|
|
/// <param name="keyVerion"></param>
|
|
public CipherKey(CipherType cipher)
|
|
{
|
|
_Cipher = cipher;
|
|
_Key = GenerateEmptyKey(cipher);
|
|
|
|
if (cipher == CipherType.AES)
|
|
{
|
|
_KeyVersion = 0x10;
|
|
}
|
|
else
|
|
{
|
|
_KeyVersion = 0x00;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
/// <summary>
|
|
/// Key as Array
|
|
/// </summary>
|
|
public byte[] _Key { get; private set; }
|
|
|
|
/// <summary>
|
|
/// CipherType of Key
|
|
/// </summary>
|
|
public CipherType _Cipher { get; private set; }
|
|
|
|
/// <summary>
|
|
/// KeyVersion of Key
|
|
/// For AES 0x10 is minimum
|
|
/// </summary>
|
|
public byte _KeyVersion { get; private set; }
|
|
#endregion
|
|
|
|
#region Methods
|
|
/// <summary>
|
|
/// Generate Empty Key for CipherType
|
|
/// </summary>
|
|
/// <param name="cipher">Type of Cipher</param>
|
|
public byte[] GenerateEmptyKey(CipherType cipher)
|
|
{
|
|
uint size = GetKeySize(cipher);
|
|
|
|
byte[] key = new byte[size];
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
key[i] = 0;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check Key Array
|
|
/// </summary>
|
|
/// <param name="key">Key</param>
|
|
/// <param name="cipher">Cipher Type of Key</param>
|
|
public bool CheckKey(byte[] key, CipherType cipher)
|
|
{
|
|
if (key.Length != GetKeySize(cipher))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get KeySize for CipherType
|
|
/// </summary>
|
|
/// <param name="cipher">Type of Cipher</param>
|
|
public uint GetKeySize(CipherType cipher)
|
|
{
|
|
switch (cipher)
|
|
{
|
|
case CipherType.TDES:
|
|
return 16;
|
|
case CipherType.TDES_2K:
|
|
return 16;
|
|
case CipherType.TDES_3K:
|
|
return 24;
|
|
case CipherType.AES:
|
|
return 16;
|
|
default:
|
|
throw new ArgumentOutOfRangeException("Unknown CipherType.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set Key Version for DES/TDES Keys
|
|
/// KeyVersion is stored in the LSBits of the first 8 Bytes
|
|
/// Parity Bits are not used from DESFire Cars
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <param name="version"></param>
|
|
/// <returns></returns>
|
|
public byte[] SetKeyVersion(byte[] key, byte version)
|
|
{
|
|
byte[] pow2 = new byte[]
|
|
{
|
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
|
};
|
|
|
|
byte[] new_key = new byte[key.Length];
|
|
key.CopyTo(new_key, 0);
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((version & pow2[i]) > 0)
|
|
{
|
|
new_key[i] = (byte)(new_key[5] | 0x01);
|
|
}
|
|
else
|
|
{
|
|
new_key[i] = (byte)(new_key[5] & 0x7F);
|
|
}
|
|
}
|
|
|
|
return new_key;
|
|
}
|
|
#endregion
|
|
}
|
|
} |