using System; namespace NFC.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 } }