private byte[] DumpMifareStandard(PcscSdk.MifareStandard.AccessHandler mifare) { byte[] madData = new byte[32]; mifare.Read(1, PcscSdk.MifareStandard.GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 0).CopyTo(madData, 0); mifare.Read(2, PcscSdk.MifareStandard.GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 0).CopyTo(madData, 16); byte crc = madData[0]; byte calcCrc = PcscSdk.MifareStandard.CRC8.Calc(madData.Skip(1).ToArray()); if (crc != calcCrc) { throw new NfcHandlerException("MAD CRC mismatch. 0x" + BitConverter.ToString(new[] { crc }) + " != 0x" + BitConverter.ToString(new[] { calcCrc })); } StatusMessage?.Invoke("CRC 0x" + BitConverter.ToString(new[] { crc }) + " OK"); using (MemoryStream mem = new MemoryStream()) { for (int sec = 1; sec < 16; sec++) { if (madData[sec * 2] != 0x03 || madData[sec * 2 + 1] != 0xE1) { continue; } for (int block = sec * 4; block < sec * 4 + 3; block++) { mem.Write(mifare.Read((ushort)block, PcscSdk.MifareStandard.GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 1), 0, 16); } } return(mem.ToArray()); } }
private byte InitAndGetGPMifareStandard(PcscSdk.MifareStandard.AccessHandler mifare) { mifare.LoadKey(new byte[] { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 }, 0); StatusMessage?.Invoke("Loaded public MAD key in slot 0."); mifare.LoadKey(new byte[] { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 }, 1); StatusMessage?.Invoke("Loaded public NDEF key in slot 1."); byte[] infoData; try { infoData = mifare.Read(3, GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 0); } catch (Exception) { StatusMessage?.Invoke("Failed reading with default key."); mifare.LoadKey(PcscSdk.MifareStandard.DefaultKeys.FactoryDefault, 0); StatusMessage?.Invoke("Loaded factory default key in slot 0."); infoData = mifare.Read(3, GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 0); StatusMessage?.Invoke("Card uses factory default key!"); } byte gpByte = infoData[9]; StatusMessage?.Invoke("General purpose byte: " + BitConverter.ToString(new[] { gpByte })); return(gpByte); }
private void WriteNdefToMifareStandard(PcscSdk.MifareStandard.AccessHandler mifare, byte[] ndefData) { InitializeMifareStandard(mifare); const int capacity = 15 * 3 * 16; byte[] wrappedData = GenerateTLVData(ndefData); if (wrappedData.Length > capacity) { throw new NfcHandlerException("Data size of " + wrappedData.Length + " bytes exceeds capacity of " + capacity + " bytes!"); } int data_length = wrappedData.Length; Array.Resize(ref wrappedData, (data_length / 16) * 16 + 16); byte writeBlock = 3; for (byte pos = 0; pos < wrappedData.Length; pos += 16) { if (++writeBlock % 4 == 3) { writeBlock++; } mifare.Write(writeBlock, wrappedData.Skip(pos).Take(16).ToArray(), GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 1); } StatusMessage?.Invoke("Written " + data_length + " bytes of data. Ndef message length is " + ndefData.Length + " bytes."); }
private void HandleMifareStandard(ICardReader reader) { var mifare = new PcscSdk.MifareStandard.AccessHandler(reader); StatusMessage?.Invoke("Handling as Mifare Standard 1K"); byte[] uid = mifare.GetUid(); StatusMessage?.Invoke("UID: " + BitConverter.ToString(uid)); Array.Resize(ref uid, uid.Length + 1); uid[uid.Length - 1] = 0xBB; NewTagUid?.Invoke(uid); byte gpByte = InitAndGetGPMifareStandard(mifare); bool usesMad = (gpByte & 0x80) != 0; bool multiApp = (gpByte & 0x40) != 0; int madVersion = gpByte & 0x03; StatusMessage?.Invoke("Uses MAD: " + usesMad + "; Multi App: " + multiApp + "; Version: " + madVersion); if (ndefDataToWrite != null) { WriteNdefToMifareStandard(mifare, ndefDataToWrite); ndefDataToWrite = null; } else { if (!usesMad) { throw new NfcHandlerException("No MAD in use"); } if (madVersion != 1) { throw new NfcHandlerException("Unsupported MAD version: " + madVersion + " (Only version 1 is supported)"); } byte[] data = DumpMifareStandard(mifare); ParseTLVData(data); } }
private void InitializeMifareStandard(PcscSdk.MifareStandard.AccessHandler mifare) { byte[] mad1 = mifare.Read(1, PcscSdk.MifareStandard.GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 0); byte[] mad2 = mifare.Read(2, PcscSdk.MifareStandard.GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 0); // One of my readers only has two key slots, another one does not allow overwriting them, but has at least 3. So here we go... // Also, the Microsoft IFD emulation(?) reports 0x0000 in response, but it still seems to have worked. byte factoryKeySlot = 0; try { mifare.LoadKey(PcscSdk.MifareStandard.DefaultKeys.FactoryDefault, 0); StatusMessage?.Invoke("Loaded factory default key in slot 0."); } catch (ApduFailedException e) { if (e.Response.SW == 0x0000 && e.Response.ResponseData.Length == 0 && mifare.CardReader.Name.Contains("Microsoft IFD")) { StatusMessage?.Invoke("Loaded factory default key in slot 0. (MS Quirk)"); } else { StatusMessage?.Invoke("Could not re-load to slot 0, trying slot 2: " + e.Message); mifare.LoadKey(PcscSdk.MifareStandard.DefaultKeys.FactoryDefault, 2); StatusMessage?.Invoke("Loaded factory default key in slot 2."); factoryKeySlot = 2; } } if (!mad1.SequenceEqual(ndefMadData[1]) || !mad2.SequenceEqual(ndefMadData[2])) { StatusMessage?.Invoke("Writing NDEF MAD block."); for (byte block = 1; block < 4; block++) { StatusMessage?.Invoke("Writing MAD block " + block); try { mifare.Write(block, ndefMadData[block], GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, factoryKeySlot); } catch (Exception) { mifare.Write(block, ndefMadData[block], GeneralAuthenticate.GeneralAuthenticateKeyType.PicoTagPassKeyB, factoryKeySlot); } } } for (int sector = 1; sector < 16; sector++) { byte block = (byte)(sector * 4 + 3); try { for (int i = 1; i < 4; i++) { var authRes = mifare.CardReader.Transceive(new PcscSdk.MifareStandard.GeneralAuthenticate((byte)(block - i), 1, GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA)); if (!authRes.Succeeded) { StatusMessage?.Invoke("NDEF read authentication failed, trying trailer rewrite."); throw new Exception(); } } byte[] sectorIdent = mifare.Read(block, GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, 1); if (!sectorIdent.SequenceEqual(ndefComparator)) { throw new Exception(); } } catch (Exception) { StatusMessage?.Invoke("Writing NDEF trailer into sector " + sector); try { mifare.Write(block, ndefSectorIdent, GeneralAuthenticate.GeneralAuthenticateKeyType.MifareKeyA, factoryKeySlot); } catch (Exception) { mifare.Write(block, ndefSectorIdent, GeneralAuthenticate.GeneralAuthenticateKeyType.PicoTagPassKeyB, factoryKeySlot); } } } StatusMessage?.Invoke("Tag is NDEF formated"); }