Skip to content

Commit

Permalink
feat: Implement multiple custom saved cards file parsers(#370)
Browse files Browse the repository at this point in the history
  • Loading branch information
GameTec-live authored Oct 30, 2023
1 parent 751f4d2 commit 08a8d67
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 3 deletions.
153 changes: 152 additions & 1 deletion chameleonultragui/lib/gui/page/saved_cards.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -31,6 +32,142 @@ class SavedCardsPage extends StatefulWidget {
class SavedCardsPageState extends State<SavedCardsPage> {
MifareClassicType selectedType = MifareClassicType.m1k;

CardSave pm3JsonToCardSave(String json) {
Map<String, dynamic> 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<int> atqa = [
int.parse(atqaString.substring(2), radix: 16),
int.parse(atqaString.substring(0, 2), radix: 16)
];
final List<int> ats = [];
final String name = uid;
const Color color = Colors.deepOrange;
final TagType tag;
List<Uint8List> tagData = [];

List<String> blocks = [];
Map<String, dynamic> blockData = data['blocks'] as Map<String, dynamic>;
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<int> atqa = [
int.parse(atqaString.substring(0, 2), radix: 16),
int.parse(atqaString.substring(2), radix: 16)
];
final List<int> ats = [];
final String name = uid;
const Color color = Colors.deepOrange;
final TagType tag;
List<Uint8List> tagData = [];
List<String> 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<int> atqa = [
int.parse(atqaString.substring(2), radix: 16),
int.parse(atqaString.substring(0, 2), radix: 16)
];
final List<int> ats = [];
final String name = uid;
const Color color = Colors.deepOrange;
final TagType tag;
List<Uint8List> tagData = [];
List<String> 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<ChameleonGUIState>();
Expand Down Expand Up @@ -73,7 +210,21 @@ class SavedCardsPageState extends State<SavedCardsPage> {
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();
Expand Down
16 changes: 15 additions & 1 deletion chameleonultragui/lib/helpers/mifare_classic/general.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -216,4 +230,4 @@ List<Uint8List> mfClassicGetKeysFromDump(List<Uint8List> dump) {
}

return keys;
}
}
1 change: 0 additions & 1 deletion chameleonultragui/lib/sharedprefsprovider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 08a8d67

Please sign in to comment.