private void ParseTLVData(byte[] data) { using (MemoryStream stream = new MemoryStream(data)) using (BinaryReader reader = new BinaryReader(stream)) { while (stream.Position < stream.Length) { byte tag = reader.ReadByte(); int length = 0; byte[] val = null; if (tag != 0x00 && tag != 0xFE) { length = reader.ReadByte(); if (length >= 0xFF) { byte[] lengthBytes = reader.ReadBytes(2); if (BitConverter.IsLittleEndian) { Array.Reverse(lengthBytes); } length = BitConverter.ToUInt16(lengthBytes, 0); } val = length > 0 ? reader.ReadBytes(length) : null; } switch (tag) { case 0x00: StatusMessage?.Invoke("Skipping NULL TLV"); break; case 0x01: StatusMessage?.Invoke("Skipping Lock Control TLV"); break; case 0x02: StatusMessage?.Invoke("Skipping Memory Control TLV"); break; case 0xFE: StatusMessage?.Invoke("Reached terminator TLV"); return; case 0x03: if (val != null) { StatusMessage?.Invoke("Found NDEF TLV (" + length + " bytes)"); NdefMessage msg = NdefMessage.FromByteArray(val); ReceiveNdefMessage?.Invoke(msg); } else { StatusMessage?.Invoke("Found empty NDEF TLV"); } break; default: StatusMessage?.Invoke("Skipping unknown TLV " + BitConverter.ToString(new byte[] { tag })); break; } } } }
private void HandleHCEClient(ICardReader reader) { StatusMessage?.Invoke("Attemtping to talk to Android HCE device."); var selectCmd = new Iso7816.SelectCommand(FLAGCARRIER_HCE_AID, 0); var res = reader.Transceive(selectCmd); if (res.SW == 0x6a82) { ErrorMessage?.Invoke("Device has no idea who we are."); return; } else if (!res.Succeeded) { ErrorMessage?.Invoke("Failed communicating with device: " + res.ToString()); return; } StatusMessage?.Invoke("Connected to FlagCarrier HCE device!"); byte[] challengeToken = new byte[32]; random.NextBytes(challengeToken, 0, challengeToken.Length); var updateCmd = new Iso7816.UpdateBinaryCommand(challengeToken); res = reader.Transceive(updateCmd); if (res.SW == 0x6A82) { ErrorMessage?.Invoke("HCE Device does not have any data for us."); return; } if (!res.Succeeded) { ErrorMessage?.Invoke("Failed sending challenge token: " + res.ToString()); return; } StatusMessage?.Invoke("Sent challenge token."); byte[] ndefData = new byte[0]; const int len = 250; int offset = 0; do { var readCmd = new Iso7816.ReadBinaryCommand(len, offset); res = reader.Transceive(readCmd); if (!res.Succeeded) { ErrorMessage?.Invoke("Failed reading data at " + offset + ": " + res.ToString()); return; } if (res.ResponseData == null || res.ResponseData.Length == 0) { break; } Array.Resize(ref ndefData, ndefData.Length + res.ResponseData.Length); res.ResponseData.CopyTo(ndefData, offset); offset += res.ResponseData.Length; } while (res.ResponseData.Length == len); StatusMessage?.Invoke("Read " + ndefData.Length + " bytes of ndef data from device."); NdefMessage msg = NdefMessage.FromByteArray(ndefData); NewTagUid?.Invoke(challengeToken); ReceiveNdefMessage?.Invoke(msg); var eraseCmd = new Iso7816.EraseBinaryCommand(); res = reader.Transceive(eraseCmd); if (!res.Succeeded) { ErrorMessage?.Invoke("Failed confirming transaction to device."); } }