using System;
namespace NFC.Helper.Crypto
{
///
/// Key for DESFire Card
///
public class CipherKey
{
#region Constructors
///
/// Creates Key from Array
///
/// Key
/// Cipher for Key
/// Version of Key
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;
}
}
///
/// Creates Key from String
///
/// Key
/// Cipher for Key
/// Version of Key
public CipherKey(string key, CipherType cipher, byte keyVersion) : this(HexConverter.ConvertFromHexString(key), cipher, keyVersion)
{
}
///
/// Generates Empty Key
///
/// Cipher for Key
///
public CipherKey(CipherType cipher)
{
_Cipher = cipher;
_Key = GenerateEmptyKey(cipher);
if (cipher == CipherType.AES)
{
_KeyVersion = 0x10;
}
else
{
_KeyVersion = 0x00;
}
}
#endregion
#region Properties
///
/// Key as Array
///
public byte[] _Key { get; private set; }
///
/// CipherType of Key
///
public CipherType _Cipher { get; private set; }
///
/// KeyVersion of Key
/// For AES 0x10 is minimum
///
public byte _KeyVersion { get; private set; }
#endregion
#region Methods
///
/// Generate Empty Key for CipherType
///
/// Type of Cipher
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;
}
///
/// Check Key Array
///
/// Key
/// Cipher Type of Key
public bool CheckKey(byte[] key, CipherType cipher)
{
if (key.Length != GetKeySize(cipher))
{
return false;
}
else
{
return true;
}
}
///
/// Get KeySize for CipherType
///
/// Type of Cipher
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.");
}
}
///
/// 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
///
///
///
///
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
}
}