public static void MifareTest() { using (var context = new NfcContext()) using (var device = context.OpenDevice()) // Try to open the NFC reader { MifareClassic mfc = new MifareClassic(device); mfc.InitialDevice(); mfc.SelectCard(); mfc.Authentication(0, KeyType.KeyA, 0xFFFFFFFFFFFFu); var block0 = mfc.ReadBlock(0); Program.PrintHex(block0, 16); mfc.Authentication(1, KeyType.KeyA, 0xFFFFFFFFFFFFu); mfc.WriteBlock(4, new byte[16] { 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); var block4 = mfc.ReadBlock(4); Program.PrintHex(block4, 16); Console.ReadLine(); } }
static void Main(string[] args) { byte[] abtRawUid = new byte[12]; byte[] abtAtqa = new byte[2]; byte abtSak = 0; byte[] abtAts = new byte[MAX_FRAME_LEN]; uint szAts = 0; bool isoAtsSupported = false; bool forceRats = false; uint szCL = 1; try { using (var context = new NfcContext()) using (device = context.OpenDevice()) // Try to open the NFC reader { // Initialise NFC device as "initiator" device.InitiatorInit(); // Configure the CRC device.DeviceSetPropertyBool(NfcProperty.HandleCrc, false); // Use raw send/receive methods device.DeviceSetPropertyBool(NfcProperty.EasyFraming, false); // Disable 14443-4 autoswitching device.DeviceSetPropertyBool(NfcProperty.AutoIso14443_4, false); WriteLine("NFC reader: {0} opened", device.Name); WriteLine(); // Send the 7 bits request command specified in ISO 14443A (0x26) TransmitBits(abtReqa, 7); Array.Copy(abtRx, abtAtqa, 2); // Anti-collision TransmitBytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { WriteLine("WARNING: BCC check failed!"); } // Save the UID CL1 Array.Copy(abtRx, abtRawUid, 4); //Prepare and send CL1 Select-Command Array.Copy(abtRx, 0, abtSelectTag, 2, 5); Iso14443aCrcAppend(abtSelectTag, 7); TransmitBytes(abtSelectTag, 9); abtSak = abtRx[0]; #region CL // Test if we are dealing with a CL2 if ((abtSak & CASCADE_BIT) != 0) { szCL = 2; // or more // Check answer if (abtRawUid[0] != 0x88) { WriteLine("WARNING: Cascade bit set but CT != 0x88!"); } } if (szCL == 2) { // We have to do the anti-collision for cascade level 2 // Prepare CL2 commands abtSelectAll[0] = 0x95; // Anti-collision TransmitBytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { WriteLine("WARNING: BCC check failed!"); } // Save UID CL2 Array.Copy(abtRx, 0, abtRawUid, 4, 4); // Selection abtSelectTag[0] = 0x95; Array.Copy(abtRx, 0, abtSelectTag, 2, 5); Iso14443aCrcAppend(abtSelectTag, 7); TransmitBytes(abtSelectTag, 9); abtSak = abtRx[0]; // Test if we are dealing with a CL3 if ((abtSak & CASCADE_BIT) != 0) { szCL = 3; // Check answer if (abtRawUid[0] != 0x88) { WriteLine("WARNING: Cascade bit set but CT != 0x88!"); } } if (szCL == 3) { // We have to do the anti-collision for cascade level 3 // Prepare and send CL3 AC-Command abtSelectAll[0] = 0x97; TransmitBytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { WriteLine("WARNING: BCC check failed!"); } // Save UID CL3 Array.Copy(abtRx, 0, abtRawUid, 8, 4); // Prepare and send final Select-Command abtSelectTag[0] = 0x97; Array.Copy(abtRx, 0, abtSelectTag, 2, 5); Iso14443aCrcAppend(abtSelectTag, 7); TransmitBytes(abtSelectTag, 9); abtSak = abtRx[0]; } } #endregion // Request ATS, this only applies to tags that support ISO 14443A-4 if ((abtRx[0] & SAK_FLAG_ATS_SUPPORTED) != 0) { isoAtsSupported = true; } if ((abtRx[0] & SAK_FLAG_ATS_SUPPORTED) != 0 || forceRats) { Iso14443aCrcAppend(abtRats, 2); int szRx = TransmitBytes(abtRats, 4); if (szRx >= 0) { Array.Copy(abtRx, abtAts, szRx); szAts = (uint)szRx; } } WriteLine(); WriteLine("驗證Block 0"); // 驗證 Block 0 Iso14443aCrcAppend(abtAuthA, 2); TransmitBytes(abtAuthA, 4); // 自己控制 Parity bit device.DeviceSetPropertyBool(NfcProperty.HandleParity, false); var nt = abtRx.ToUInt32(); var uid = abtRawUid.ToUInt32(); Write(" Nt: "); PrintHex(abtRx, 4); var crapto1 = new Crypto1(0xFFFFFFFFFFFFu); // 初始化 crapto1 狀態 feed in uid^nt and drop keystream in the first round crapto1.Crypto1Word(uid ^ nt); // 自訂讀卡機端nonce var nr = 0x01020304u; // Ar 為 suc2(nt) var ar = PrngSuccessor(nt, 64); // 加密 Nr,suc2(Nt) 和 parity bit var enNrAr = nr.GetBytes().Concat(ar.GetBytes()).ToArray(); var enNrArParity = new byte[8]; crapto1.Encrypt(enNrAr, enNrArParity, 0, 4, true); crapto1.Encrypt(enNrAr, enNrArParity, 4, 4); Write("[Nr,suc2(Nt)]: "); PrintHex(enNrAr, 8); // 送出[Nr,suc2(Nt)] device.InitiatorTransceiveBits(enNrAr, 64, enNrArParity, abtRx, MAX_FRAME_LEN, null); var enAt = new byte[4]; Array.Copy(abtRx, enAt, 4); Write(" [suc3(Nt)]: "); PrintHex(enAt, 4); // 解密[at] var at = enAt.ToUInt32() ^ crapto1.Crypto1Word(); WriteLine("At: {0:x8} == suc3(Nt):{1:x8}", at, PrngSuccessor(nt, 96)); // 讀取 Block for (byte i = 0; i < 4; i++) { ReadBlock(crapto1, i); } WriteLine(); WriteLine("Nested驗證 Block 4"); // Nested驗證 Block 4 abtAuthA[1] = 4; Iso14443aCrcAppend(abtAuthA, 2); var enAuth = abtAuthA.ToArray(); var enAuthParity = new byte[4]; crapto1.Encrypt(enAuth, enAuthParity, 0, 4); device.InitiatorTransceiveBits(enAuth, 32, enAuthParity, abtRx, MAX_FRAME_LEN, null); // 開始Nested驗證的新crypto1密鑰 crapto1 = new Crypto1(0xFFFFFFFFFFFFu); Write(" 未解密Nt: "); PrintHex(abtRx, 4); var enNt = abtRx.ToUInt32(); // 初始化 crapto1 狀態 用加密的Nt,並解出明文nt nt = enNt ^ crapto1.Crypto1Word(uid ^ enNt, true); Write(" Nt: "); PrintHex(nt.GetBytes(), 4); // 自訂讀卡機端nonce nr = 0x01020304u; // Ar 為 suc2(nt) ar = PrngSuccessor(nt, 64); // 加密 Nr,suc2(Nt) 和 parity bit enNrAr = nr.GetBytes().Concat(ar.GetBytes()).ToArray(); enNrArParity = new byte[8]; crapto1.Encrypt(enNrAr, enNrArParity, 0, 4, true); crapto1.Encrypt(enNrAr, enNrArParity, 4, 4); Write("[Nr,suc2(Nt)]: "); PrintHex(enNrAr, 8); // 送出[Nr,suc2(Nt)] var res = device.InitiatorTransceiveBits(enNrAr, 64, enNrArParity, abtRx, MAX_FRAME_LEN, null); enAt = new byte[4]; Array.Copy(abtRx, enAt, 4); Write(" [suc3(Nt)]: "); PrintHex(enAt, 4); // 解密[at] at = enAt.ToUInt32() ^ crapto1.Crypto1Word(); WriteLine("At: {0:x8} == suc3(Nt):{1:x8}", at, PrngSuccessor(nt, 96)); // 寫入 Block4 WriteBlock(crapto1, 4, new byte[16] { 65, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); // 讀取 Block for (byte i = 4; i < 8; i++) { ReadBlock(crapto1, i); } WriteLine(); // device.DeviceSetPropertyBool(NfcProperty.HandleParity, true); // Done, halt the tag now Iso14443aCrcAppend(abtHalt, 2); TransmitBytes(abtHalt, 4); } } catch (Exception ex) { WriteLine(ex.Message); Environment.Exit(1); } WriteLine(); WriteLine("Found tag with"); Write(" UID: "); switch (szCL) { case 1: Write("{0:x2}{1:x2}{2:x2}{3:x2}", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]); break; case 2: Write("{0:x2}{1:x2}{2:x2}", abtRawUid[1], abtRawUid[2], abtRawUid[3]); Write("{0:x2}{1:x2}{2:x2}{3:x2}", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]); break; case 3: Write("{0:x2}{1:x2}{2:x2}", abtRawUid[1], abtRawUid[2], abtRawUid[3]); Write("{0:x2}{1:x2}{2:x2}", abtRawUid[5], abtRawUid[6], abtRawUid[7]); Write("{0:x2}{1:x2}{2:x2}{3:x2}", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]); break; } WriteLine(); WriteLine("ATQA: {0:x2}{1:x2}", abtAtqa[1], abtAtqa[0]); WriteLine(" SAK: {0:x2}", abtSak); if (szAts > 1) { // if = 1, it's not actual ATS but error code if (forceRats && !isoAtsSupported) { WriteLine(" RATS forced"); } Write(" ATS: "); PrintHex(abtAts, szAts); } ReadLine(); }