static void WriteBlock(Crypto1 crapto1, byte b, byte[] blockData) { var enWrite = new byte[4] { 0xA0, b, 0, 0 }; Iso14443aCrcAppend(enWrite, 2); var enWriteParity = new byte[4]; crapto1.Encrypt(enWrite, enWriteParity, 0, 4); var resbits = device.InitiatorTransceiveBits(enWrite, 32, enWriteParity, abtRx, MAX_FRAME_LEN, null); var res = 0; for (int i = 0; i < 4; i++) { res |= ((abtRx[0] >> i) ^ crapto1.Crypto1Bit()) << i; } WriteLine("Write Cmd : " + res.ToString("x2")); if (res != 0x0A && res != 0x0E) // 0x0A ACK, 0x0E NAK { throw new Exception("Cmd Error: " + res.ToString("x2")); } var enBlock = new byte[18]; // 16byte data + 2byte crc var enBlockParity = new byte[18]; if (blockData != null) { Array.Copy(blockData, enBlock, blockData.Length > 16 ? 16 : blockData.Length); } Iso14443aCrcAppend(enBlock, 16); Write("Write Block{0,2}: ", b); PrintHex(enBlock, 16); crapto1.Encrypt(enBlock, enBlockParity, 0, 18); resbits = device.InitiatorTransceiveBits(enBlock, 144, enBlockParity, abtRx, MAX_FRAME_LEN, null); res = 0; for (int i = 0; i < 4; i++) { res |= ((abtRx[0] >> i) ^ crapto1.Crypto1Bit()) << i; } WriteLine("Write data: " + res.ToString("x2")); if (res != 0x0A && res != 0x0E) // 0x0A ACK, 0x0E NAK { throw new Exception("Cmd Error: " + res.ToString("x2")); } //var enTransfer = new byte[4] { 0xB0, b, 0, 0 }; //Nfc.Iso14443aCrcAppend(enTransfer, 2); //var enTransferParity = new byte[4]; //crapto1.Encrypt(enTransfer, enTransferParity, 0, 4); //res = device.InitiatorTransceiveBits(enTransfer, 32, enTransferParity, abtRx, MAX_FRAME_LEN, null); }
public void Authentication(byte sector, KeyType keyType, ulong key) { var auth = new byte[4] { keyType == KeyType.KeyA ? (byte)0x60 : (byte)0x61, (byte)(sector * 4), 0, 0 }; Iso14443aCrcAppend(auth, 2); var nt = 0u; var crapto1 = new Crypto1(key); if (Crypto1 == null) // 初次驗證 { Device.DeviceSetPropertyBool(NfcProperty.HandleParity, true); Device.InitiatorTransceiveBytes(auth, 4, rxBuffer, MAX_FRAME_LEN, 0); Device.DeviceSetPropertyBool(NfcProperty.HandleParity, false); nt = rxBuffer.ToUInt32(); crapto1.Crypto1Word(Uid ^ nt); } else // Nested 驗證 { var authParity = new byte[4]; Crypto1.Encrypt(auth, authParity, 0, 4); Device.InitiatorTransceiveBits(auth, 32, authParity, rxBuffer, MAX_FRAME_LEN, null); nt = rxBuffer.ToUInt32(); nt = nt ^ crapto1.Crypto1Word(Uid ^ nt, true); Crypto1 = null; } var nr = 0x01020304u; var ar = PrngSuccessor(nt, 64); 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); Device.InitiatorTransceiveBits(enNrAr, 64, enNrArParity, rxBuffer, MAX_FRAME_LEN, null); var at = rxBuffer.ToUInt32() ^ crapto1.Crypto1Word(); if (at != PrngSuccessor(nt, 96)) { throw new Exception("At error"); } Crypto1 = crapto1; _sector = sector; }
public void WriteBlock(byte b, byte[] blockData) { if (b / 4 != _sector || Crypto1 == null) { throw new Exception("Not auth"); } var write = new byte[4] { 0xA0, b, 0, 0 }; Iso14443aCrcAppend(write, 2); var writeParity = new byte[4]; Crypto1.Encrypt(write, writeParity, 0, 4); var resbits = Device.InitiatorTransceiveBits(write, 32, writeParity, rxBuffer, MAX_FRAME_LEN, null); var res = 0; for (int i = 0; i < 4; i++) { res |= ((rxBuffer[0] >> i) ^ Crypto1.Crypto1Bit()) << i; } if (res != 0x0A && res != 0x0E) // 0x0A ACK, 0x0E NAK { throw new Exception("Cmd Error: " + res.ToString("x2")); } var block = new byte[18]; // 16byte data + 2byte crc var blockParity = new byte[18]; if (blockData != null) { Array.Copy(blockData, block, blockData.Length > 16 ? 16 : blockData.Length); } Iso14443aCrcAppend(block, 16); Crypto1.Encrypt(block, blockParity, 0, 18); resbits = Device.InitiatorTransceiveBits(block, 144, blockParity, rxBuffer, MAX_FRAME_LEN, null); res = 0; for (int i = 0; i < 4; i++) { res |= ((rxBuffer[0] >> i) ^ Crypto1.Crypto1Bit()) << i; } if (res != 0x0A && res != 0x0E) // 0x0A ACK, 0x0E NAK { throw new Exception("Cmd Error: " + res.ToString("x2")); } }
static void ReadBlock(Crypto1 crapto1, byte b) { abtRead[1] = b; Iso14443aCrcAppend(abtRead, 2); var enAbtRead = abtRead.ToArray(); var enAbtReadParity = new byte[4]; crapto1.Encrypt(enAbtRead, enAbtReadParity, 0, 4); device.InitiatorTransceiveBits(enAbtRead, 32, enAbtReadParity, abtRx, MAX_FRAME_LEN, null); var block = new byte[18]; // 16byte data + 2byte crc for (int i = 0; i < 18; i++) { block[i] = (byte)(abtRx[i] ^ crapto1.Crypto1Byte()); } Write(" Block{0,2}: ", b); PrintHex(block, 16); }
public byte[] ReadBlock(byte b) { if (b / 4 != _sector || Crypto1 == null) { throw new Exception("Not auth"); } var read = new byte[4] { 0x30, b, 0, 0 }; Iso14443aCrcAppend(read, 2); var readParity = new byte[4]; Crypto1.Encrypt(read, readParity, 0, 4); Device.InitiatorTransceiveBits(read, 32, readParity, rxBuffer, MAX_FRAME_LEN, null); for (int i = 0; i < 18; i++) // 16byte data + 2byte crc { rxBuffer[i] ^= Crypto1.Crypto1Byte(); } return(rxBuffer.Take(16).ToArray()); }
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(); }