From 08a8d67eabd5a5a97ba64e424d20fe02e27f0154 Mon Sep 17 00:00:00 2001 From: GameTec-live Date: Mon, 30 Oct 2023 20:05:34 +0100 Subject: [PATCH] feat: Implement multiple custom saved cards file parsers(#370) --- .../lib/gui/page/saved_cards.dart | 153 +++++++++++++++++- .../lib/helpers/mifare_classic/general.dart | 16 +- .../lib/sharedprefsprovider.dart | 1 - 3 files changed, 167 insertions(+), 3 deletions(-) diff --git a/chameleonultragui/lib/gui/page/saved_cards.dart b/chameleonultragui/lib/gui/page/saved_cards.dart index 2466b37b..c1524136 100644 --- a/chameleonultragui/lib/gui/page/saved_cards.dart +++ b/chameleonultragui/lib/gui/page/saved_cards.dart @@ -17,6 +17,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:provider/provider.dart'; import 'package:chameleonultragui/gui/menu/card_edit.dart'; import 'package:chameleonultragui/gui/menu/dictionary_view.dart'; +import 'package:uuid/uuid.dart'; // Localizations import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -31,6 +32,142 @@ class SavedCardsPage extends StatefulWidget { class SavedCardsPageState extends State { MifareClassicType selectedType = MifareClassicType.m1k; + CardSave pm3JsonToCardSave(String json) { + Map data = jsonDecode(json); + + final String id = const Uuid().v4(); + final String uid = data['Card']['UID'] as String; + String sakString = data['Card']['SAK'] as String; + final int sak = hexToBytes(sakString)[0]; + String atqaString = data['Card']['ATQA'] as String; + final List atqa = [ + int.parse(atqaString.substring(2), radix: 16), + int.parse(atqaString.substring(0, 2), radix: 16) + ]; + final List ats = []; + final String name = uid; + const Color color = Colors.deepOrange; + final TagType tag; + List tagData = []; + + List blocks = []; + Map blockData = data['blocks'] as Map; + for (int i = 0; blockData.containsKey(i.toString()); i++) { + blocks.add(blockData[i.toString()] as String); + } + + //Check if a block has more than 16 Bytes, Ultralight, return as unknown + if (blocks[0].length > 32) { + tag = TagType.unknown; + } else { + tag = mfClassicGetChameleonTagType(mfClassicGetCardTypeByBlockCount(blocks.length)); + } + + for (var block in blocks) { + tagData.add(hexToBytes(block)); + } + + return CardSave( + id: id, + uid: uid, + sak: sak, + name: name, + tag: tag, + data: tagData, + color: color, + ats: Uint8List.fromList(ats), + atqa: Uint8List.fromList(atqa)); + } + + CardSave flipperNfcToCardSave(String data) { + final String id = const Uuid().v4(); + final String uid = RegExp(r'UID:\s+([\dA-Fa-f ]+)').firstMatch(data)!.group(1)!; + final int sak = hexToBytes(RegExp(r'SAK:\s+([\dA-Fa-f ]+)').firstMatch(data)!.group(1)!)[0]; + String atqaString = RegExp(r'ATQA:\s+([\dA-Fa-f ]+)').firstMatch(data)!.group(1)!; + final List atqa = [ + int.parse(atqaString.substring(0, 2), radix: 16), + int.parse(atqaString.substring(2), radix: 16) + ]; + final List ats = []; + final String name = uid; + const Color color = Colors.deepOrange; + final TagType tag; + List tagData = []; + List blocks = []; + for (var block in data.split("\n")) { + if (block.startsWith("Block")) { + blocks.add(block.split(":")[1].trim().replaceAll('?', '0')); + } + } + + //Check if a block has more than 16 Bytes, Ultralight, return as unknown + if (blocks[0].replaceAll(' ', '').length > 32) { + tag = TagType.unknown; + } else { + tag = mfClassicGetChameleonTagType(mfClassicGetCardTypeByBlockCount(blocks.length)); + } + + for (var block in blocks) { + tagData.add(hexToBytesSpace(block)); + } + + return CardSave( + id: id, + uid: uid, + sak: sak, + name: name, + tag: tag, + data: tagData, + color: color, + ats: Uint8List.fromList(ats), + atqa: Uint8List.fromList(atqa)); + } + + CardSave mfctToCardSave(String data) { + final String id = const Uuid().v4(); + final String uid = data.split("\n")[1].substring(0, 8); + final int sak = hexToBytes(data.split("\n")[1].substring(10,12))[0]; + String atqaString = data.split("\n")[1].substring(12, 16); + final List atqa = [ + int.parse(atqaString.substring(2), radix: 16), + int.parse(atqaString.substring(0, 2), radix: 16) + ]; + final List ats = []; + final String name = uid; + const Color color = Colors.deepOrange; + final TagType tag; + List tagData = []; + List blocks = []; + for (var block in data.split("\n")) { + if (!block.startsWith("+Sector")) { + blocks.add(block.trim()); + } + } + + //Check if a block has more than 16 Bytes, Ultralight, return as unknown + if (blocks[0].replaceAll(' ', '').length > 32) { + tag = TagType.unknown; + } else { + tag = mfClassicGetChameleonTagType(mfClassicGetCardTypeByBlockCount(blocks.length)); + } + + for (var block in blocks) { + tagData.add(hexToBytesSpace(block)); + } + + return CardSave( + id: id, + uid: uid, + sak: sak, + name: name, + tag: tag, + data: tagData, + color: color, + ats: Uint8List.fromList(ats), + atqa: Uint8List.fromList(atqa)); + } + + @override Widget build(BuildContext context) { var appState = context.watch(); @@ -73,7 +210,21 @@ class SavedCardsPageState extends State { var string = const Utf8Decoder().convert(contents); var tags = appState.sharedPreferencesProvider.getCards(); - var tag = CardSave.fromJson(string); + CardSave tag; + if (string.contains("\"Created\": \"proxmark3\",")) { + // PM3 JSON + tag = pm3JsonToCardSave(string); + } else if (string.contains("Filetype: Flipper NFC device")) { + // Flipper NFC + tag = flipperNfcToCardSave(string); + } else if (string.contains("+Sector: 0")) { + // Mifare Classic Tool + tag = mfctToCardSave(string); + + } else { + tag = CardSave.fromJson(string); + } + tags.add(tag); appState.sharedPreferencesProvider.setCards(tags); appState.changesMade(); diff --git a/chameleonultragui/lib/helpers/mifare_classic/general.dart b/chameleonultragui/lib/helpers/mifare_classic/general.dart index 641e9908..63c2e10c 100644 --- a/chameleonultragui/lib/helpers/mifare_classic/general.dart +++ b/chameleonultragui/lib/helpers/mifare_classic/general.dart @@ -141,6 +141,20 @@ int mfClassicGetBlockCount(MifareClassicType type, {bool isEV1 = false}) { } } +MifareClassicType mfClassicGetCardTypeByBlockCount(int blockCount) { + if (blockCount == 64 || blockCount == 72) { + return MifareClassicType.m1k; + } else if (blockCount == 128) { + return MifareClassicType.m2k; + } else if (blockCount == 256) { + return MifareClassicType.m4k; + } else if (blockCount == 20) { + return MifareClassicType.mini; + } else { + return MifareClassicType.none; + } +} + int mfClassicGetSectorTrailerBlockBySector(int sector) { if (sector < 32) { return sector * 4 + 3; @@ -216,4 +230,4 @@ List mfClassicGetKeysFromDump(List dump) { } return keys; -} +} \ No newline at end of file diff --git a/chameleonultragui/lib/sharedprefsprovider.dart b/chameleonultragui/lib/sharedprefsprovider.dart index a1a5d3af..29c3a9f5 100644 --- a/chameleonultragui/lib/sharedprefsprovider.dart +++ b/chameleonultragui/lib/sharedprefsprovider.dart @@ -8,7 +8,6 @@ import 'package:uuid/uuid.dart'; // Localizations import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class Dictionary { String id; String name;