예제 #1
0
 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();
         }
 }
예제 #2
0
        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();
        }