Skip to content

Commit

Permalink
Implement new protocol changes (#276)
Browse files Browse the repository at this point in the history
Add support for the new protocol (v2.0), add Static Nested key recovery and add ATS reading support
  • Loading branch information
Foxushka authored Sep 26, 2023
1 parent ff9488a commit e265b93
Show file tree
Hide file tree
Showing 17 changed files with 742 additions and 176 deletions.
197 changes: 129 additions & 68 deletions chameleonultragui/lib/bridge/chameleon.dart

Large diffs are not rendered by default.

76 changes: 49 additions & 27 deletions chameleonultragui/lib/gui/menu/card_edit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ class CardEditMenuState extends State<CardEditMenu> {
String uid = "";
int sak = 0;
Uint8List atqa = Uint8List.fromList([]);
Uint8List ats = Uint8List.fromList([]);
TextEditingController uidController = TextEditingController();
TextEditingController sak4Controller = TextEditingController();
TextEditingController atqa4Controller = TextEditingController();
TextEditingController sakController = TextEditingController();
TextEditingController atqaController = TextEditingController();
TextEditingController nameController = TextEditingController();
TextEditingController atsController = TextEditingController();
Color pickerColor = Colors.deepOrange;
Color currentColor = Colors.deepOrange;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Expand All @@ -38,11 +40,13 @@ class CardEditMenuState extends State<CardEditMenu> {
selectedType = widget.tagSave.tag;
uid = widget.tagSave.uid;
sak = widget.tagSave.sak;
ats = widget.tagSave.ats;
atqa = Uint8List.fromList(widget.tagSave.atqa);
uidController = TextEditingController(text: uid);
sak4Controller =
sakController =
TextEditingController(text: bytesToHexSpace(Uint8List.fromList([sak])));
atqa4Controller = TextEditingController(text: bytesToHexSpace(atqa));
atqaController = TextEditingController(text: bytesToHexSpace(atqa));
atsController = TextEditingController(text: bytesToHexSpace(ats));
nameController = TextEditingController(text: widget.tagSave.name);
pickerColor = widget.tagSave.color;
currentColor = widget.tagSave.color;
Expand Down Expand Up @@ -156,21 +160,23 @@ class CardEditMenuState extends State<CardEditMenu> {
controller: uidController,
decoration: InputDecoration(
labelText: localizations.uid,
hintText: localizations.enter_something("UID")),
hintText:
localizations.enter_something(localizations.uid)),
validator: (value) {
if (value == null || value.isEmpty) {
return localizations.please_enter_something("UID");
return localizations
.please_enter_something(localizations.uid);
}
if (!(value.replaceAll(" ", "").length == 14 ||
value.replaceAll(" ", "").length == 8) &&
chameleonTagToFrequency(selectedType) !=
TagFrequency.lf) {
return localizations.must_or(4, 7, "UID");
return localizations.must_or(4, 7, localizations.uid);
}
if (value.replaceAll(" ", "").length != 10 &&
chameleonTagToFrequency(selectedType) ==
TagFrequency.lf) {
return localizations.must_be(5, "UID");
return localizations.must_be(5, localizations.uid);
}
return null;
},
Expand All @@ -180,21 +186,23 @@ class CardEditMenuState extends State<CardEditMenu> {
visible:
chameleonTagToFrequency(selectedType) != TagFrequency.lf,
child: TextFormField(
controller: sak4Controller,
controller: sakController,
decoration: InputDecoration(
labelText: localizations.sak,
hintText: localizations.enter_something("SAK")),
hintText:
localizations.enter_something(localizations.sak)),
validator: (value) {
if (value == null ||
value.isEmpty &&
chameleonTagToFrequency(selectedType) !=
TagFrequency.lf) {
return localizations.please_enter_something("SAK");
return localizations
.please_enter_something(localizations.sak);
}
if (value.replaceAll(" ", "").length != 2 &&
chameleonTagToFrequency(selectedType) !=
TagFrequency.lf) {
return localizations.must_be(1, "SAK");
return localizations.must_be(1, localizations.sak);
}
return null;
},
Expand All @@ -205,26 +213,40 @@ class CardEditMenuState extends State<CardEditMenu> {
visible:
chameleonTagToFrequency(selectedType) != TagFrequency.lf,
child: TextFormField(
controller: atqa4Controller,
controller: atqaController,
decoration: InputDecoration(
labelText: localizations.atqa,
hintText: localizations.enter_something("ATQA")),
hintText:
localizations.enter_something(localizations.atqa)),
validator: (value) {
if (value == null ||
value.isEmpty &&
chameleonTagToFrequency(selectedType) !=
TagFrequency.lf) {
return localizations.please_enter_something("ATQA");
return localizations
.please_enter_something(localizations.atqa);
}
if (value.replaceAll(" ", "").length != 4 &&
chameleonTagToFrequency(selectedType) !=
TagFrequency.lf) {
return localizations.must_be(2, "ATQA");
return localizations.must_be(2, localizations.atqa);
}
return null;
},
),
),
const SizedBox(height: 20),
Visibility(
visible:
chameleonTagToFrequency(selectedType) != TagFrequency.lf,
child: TextFormField(
controller: atsController,
decoration: InputDecoration(
labelText: localizations.ats,
hintText:
localizations.enter_something(localizations.ats)),
),
),
const SizedBox(height: 40),
]),

Expand Down Expand Up @@ -257,17 +279,17 @@ class CardEditMenuState extends State<CardEditMenu> {
}

var tag = CardSave(
id: widget.tagSave.uid,
name: nameController.text,
sak: chameleonTagToFrequency(selectedType) == TagFrequency.lf
? widget.tagSave.sak
: hexToBytes(sak4Controller.text.replaceAll(" ", ""))[0],
atqa: hexToBytes(atqa4Controller.text.replaceAll(" ", "")),
uid: uidController.text,
tag: selectedType,
data: widget.tagSave.data,
color: currentColor,
);
id: widget.tagSave.uid,
name: nameController.text,
sak: chameleonTagToFrequency(selectedType) == TagFrequency.lf
? widget.tagSave.sak
: hexToBytes(sakController.text.replaceAll(" ", ""))[0],
atqa: hexToBytes(atqaController.text.replaceAll(" ", "")),
uid: uidController.text,
tag: selectedType,
data: widget.tagSave.data,
color: currentColor,
ats: hexToBytes(atsController.text.replaceAll(" ", "")));

var tags = appState.sharedPreferencesProvider.getCards();
List<CardSave> output = [];
Expand Down
9 changes: 6 additions & 3 deletions chameleonultragui/lib/gui/menu/slot_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class SlotSettingsState extends State<SlotSettings> {

if (!isRun) {
await appState.communicator!.activateSlot(widget.slot);
isEnabled = (await appState.communicator!.getEnabledSlots())[widget.slot];
var enabledSlots = await appState.communicator!.getEnabledSlots();
isEnabled = enabledSlots[widget.slot].$1 || enabledSlots[widget.slot].$2;
var data = (await appState.communicator!.getMf1EmulatorConfig());
isDetection = data.$1;
if (isDetection) {
Expand Down Expand Up @@ -176,8 +177,10 @@ class SlotSettingsState extends State<SlotSettings> {
items: [localizations.enabled, localizations.disabled],
selectedValue: isEnabled ? 0 : 1,
onChange: (int index) async {
await appState.communicator!
.enableSlot(widget.slot, index == 0 ? true : false);
await appState.communicator!.enableSlot(widget.slot,
TagFrequency.hf, index == 0 ? true : false);
await appState.communicator!.enableSlot(widget.slot,
TagFrequency.lf, index == 0 ? true : false);

widget.refresh(widget.slot);
}),
Expand Down
50 changes: 50 additions & 0 deletions chameleonultragui/lib/gui/page/debug.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,56 @@ class DebugPage extends StatelessWidget {
]),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
await appState.communicator!.setReaderDeviceMode(true);
var distance = await appState.communicator!.getMf1NTDistance(
50,
0x60,
Uint8List.fromList([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
bool found = false;
for (var i = 0; i < 0xFF && !found; i++) {
var nonces = await appState.communicator!
.getMf1NestedNonces(
50,
0x60,
Uint8List.fromList(
[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]),
0,
0x61,
isStaticNested: true);
var nested = StaticNestedDart(
uid: distance.uid,
keyType: 0x61,
nt0: nonces.nonces[0].nt,
nt0Enc: nonces.nonces[0].ntEnc,
nt1: nonces.nonces[1].nt,
nt1Enc: nonces.nonces[1].ntEnc);

var keys = await recovery.static_nested(nested);
if (keys.isNotEmpty) {
appState.log!.d("Found keys: $keys. Checking them...");
for (var key in keys) {
var keyBytes = u64ToBytes(key);
if ((await appState.communicator!
.mf1Auth(0x03, 0x61, keyBytes.sublist(2, 8))) ==
true) {
appState.log!.i(
"Found valid key! Key ${bytesToHex(keyBytes.sublist(2, 8))}");
found = true;
break;
}
}
} else {
appState.log!.d("Can't find keys, retrying...");
}
}
},
child: Column(children: [
Text(localizations.static_nested_attack),
]),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
await appState.communicator!.setReaderDeviceMode(true);
Expand Down
60 changes: 57 additions & 3 deletions chameleonultragui/lib/gui/page/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class HomePage extends StatefulWidget {
}

class HomePageState extends State<HomePage> {
var selectedSlot = 1;
int selectedSlot = 1;
bool isLegacyFirmware = false;

@override
void initState() {
Expand Down Expand Up @@ -94,8 +95,9 @@ class HomePageState extends State<HomePage> {
Future<List<String>> getVersion() async {
var appState = context.read<ChameleonGUIState>();
String commitHash = "";
String firmwareVersion =
numToVerCode(await appState.communicator!.getFirmwareVersion());
var firmware = await appState.communicator!.getFirmwareVersion();
isLegacyFirmware = firmware.$1;
String firmwareVersion = numToVerCode(firmware.$2);

try {
commitHash = await appState.communicator!.getGitCommitHash();
Expand All @@ -109,6 +111,58 @@ class HomePageState extends State<HomePage> {
}
}

if (context.mounted && isLegacyFirmware) {
var localizations = AppLocalizations.of(context)!;
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(localizations.outdated_protocol),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(localizations.outdated_protocol_description_1),
Text(localizations.outdated_protocol_description_2),
Text(localizations.outdated_protocol_description_3),
],
),
),
actions: <Widget>[
TextButton(
child: Text(localizations.update),
onPressed: () async {
Navigator.of(context).pop();
var localizations = AppLocalizations.of(context)!;
var scaffoldMessenger = ScaffoldMessenger.of(context);
var snackBar = SnackBar(
content: Text(localizations.downloading_fw(
chameleonDeviceName(appState.connector!.device))),
action: SnackBarAction(
label: localizations.close,
onPressed: () {
scaffoldMessenger.hideCurrentSnackBar();
},
),
);

scaffoldMessenger.showSnackBar(snackBar);
await flashFirmware(appState,
scaffoldMessenger: scaffoldMessenger);
},
),
TextButton(
child: Text(localizations.skip),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}

return ["$firmwareVersion ($commitHash)", commitHash];
}

Expand Down
Loading

0 comments on commit e265b93

Please sign in to comment.