Warum scheitert die AES -Authentifizierung in meiner Flutter -App für Mifare -Desfire -Karten?Android

Forum für diejenigen, die für Android programmieren
Anonymous
 Warum scheitert die AES -Authentifizierung in meiner Flutter -App für Mifare -Desfire -Karten?

Post by Anonymous »

Ich erstelle eine Flutter -App, die flutter_nfc_kit verwendet, um mit einer Mifare Desfire EV3 -Karte zu kommunizieren, und ich versuche, eine vollständig verschlüsselte Kommunikation zu unterstützen - das heißt, authentifizieren mit der Karte, schreiben Sie eine Datei sicher und lesen Sie sie zurück. Ich verwende auch Pointycastle für die kryptografischen Operationen (AES CBC, CMAC, CRC32 usw.), alle in Dart. Ich möchte dies nativ in Flutter/Dart tun - keine Plattformkanäle, Java oder Taplinx. (NFCTAGTYPE.ISO7816). < /P>
Aber ich denke, die Macs oder CRCs sind falsch. Die Karte gibt nur 91 7e zurück. Es ist schwer zu erkennen, ob ich die falsche IV, die Polsterung, die Mac -Methode oder die Methode verwende. Wickeln Sie jeden verschlüsselten Befehl (einschließlich Dateierstellung, Lesen/Schreiben) mit CMAC- oder Mac4-Logik manuell ein? Es ist kurz und enthält nur einen relevanten Code für die Funktionsweise der Karte. < /P>

Code: Select all

import 'dart:typed_data';
import 'dart:math';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:pointycastle/export.dart';
import 'package:crc32_checksum/crc32_checksum.dart';

class Desfire {
Desfire(this._tag);
final NFCTag _tag;

late Uint8List _sk;
late Uint8List _iv;

Future writeAndRead() async {
try {
print("Attempting AES authentication...");
await _authenticateAES(Uint8List(16));
} catch (e) {
print("AES authentication failed: $e.  Falling back to legacy 3DES...");
await _authenticate3DES();
await _changeKey0ToAES();
print("Retrying AES authentication...");
await _authenticateAES(Uint8List(16));
}

await _createAppAndFile();
final data = Uint8List.fromList('hello world'.codeUnits);
await writeFile01(data);
final result = await readFile01();
final message = String.fromCharCodes(result);
print("Final read message: $message");
return message;
}

Future _authenticateAES(Uint8List key) async {
final rnd = Random.secure();
final rndA = Uint8List.fromList(List.generate(16, (_) => rnd.nextInt(256)));
final aes = AESFastEngine()..init(false, KeyParameter(key));

final r1 = await _send([0x90, 0xAA, 0, 0, 1, 0, 0]);
final encRndB = r1.sublist(0, 16);
final rndB = Uint8List(16)..setAll(0, encRndB);
aes.processBlock(encRndB, 0, rndB, 0);

print("Decrypted RndB: ${_hex(rndB)}");

final rndBrot = [...rndB.sublist(1), rndB[0]];
final ab = Uint8List.fromList([...rndA, ...rndBrot]);
final enc = AESFastEngine()..init(true, KeyParameter(key));
final tmp1 = Uint8List(16), tmp2 = Uint8List(16);
enc.processBlock(ab, 0, tmp1, 0);
enc.processBlock(ab, 16, tmp2, 0);

final r2 = await _send([0x90, 0xAF, 0, 0, 32, ...tmp1, ...tmp2, 0]);
final encRndA2 = r2.sublist(0, 16);
aes.init(false, KeyParameter(key));
final dec = Uint8List(16)..setAll(0, encRndA2);
aes.processBlock(encRndA2, 0, dec, 0);
for (int i = 0; i < 16; i++) dec[i] ^= tmp2[i];

final rot = [...rndA.sublist(1), rndA[0]];
for (int i = 0; i < 16; i++) {
if (dec[i] != rot[i]) throw 'RndA\' mismatch';
}

final sk = Uint8List(16);
for (int i = 0; i < 4; i++) {
sk[i] = rndA[i];
sk[4 + i] = rndB[i];
sk[8 + i] = rndA[12 + i];
sk[12 + i] = rndB[12 + i];
}
_sk = sk;
_iv = Uint8List(16);
print("Session key: ${_hex(_sk)}");
}

Future _authenticate3DES() async {
final r1 = await _send([0x90, 0x0A, 0, 0, 1, 0, 0]);
final encRndB = r1.sublist(0, 8);
final des = _initDes3(keyZero(), Uint8List(8), decrypt: true);
final rndB = Uint8List(8)..setAll(0, encRndB);
des.processBlock(encRndB, 0, rndB, 0);
print("Decrypted RndB (3DES): ${_hex(rndB)}");

final rndA = Uint8List.fromList(List.generate(8, (_) => Random().nextInt(256)));
final rndBrot = [...rndB.sublist(1), rndB[0]];
final ab = Uint8List.fromList([...rndA, ...rndBrot]);
final enc = _initDes3(keyZero(), Uint8List(8), decrypt: false);
final tmp = Uint8List(16);
enc.processBlock(ab, 0, tmp, 0);
enc.processBlock(ab, 8, tmp, 8);
await _send([0x90, 0xAF, 0, 0, 16, ...tmp, 0]);

final sk = Uint8List(16);
for (int i = 0; i < 4; i++) {
sk[i] = rndA[i];
sk[4 + i] = rndB[i];
sk[8 + i] = rndA[4 + i];
sk[12 + i] = rndB[4 + i];
}
_sk = sk;
_iv = Uint8List(8);
print("Session key (3DES): ${_hex(_sk)}");
}

Future _changeKey0ToAES() async {
final newKey = Uint8List(16);
final payload = [0x00, 0x80, ...newKey, ...Uint8List(16)];
final crc = _crc32(payload);
var buf = Uint8List.fromList([...payload, ...crc]);
if (buf.length % 8 != 0) buf = Uint8List.fromList([...buf, ...List.filled(8 - (buf.length % 8), 0)]);
final enc = _des3cbc(buf, encrypt: true);
_iv = enc.sublist(enc.length - 8);
final mac = _retailMac4([0xC4, 0, 0, enc.length, ...enc]);
await _send([0x90, 0xC4, 0, 0, enc.length, ...enc, ...mac, 0x00]);
}

Future _createAppAndFile() async {
final aid = [0x01, 0x00, 0x00];
await _send([0x90, 0xCA, 0x00, 0x00, 0x05, ...aid, 0x0F, 0x01, 0x00]);
await _send([0x90, 0x5A, 0, 0, 3, ...aid, 0x00]);
await _send([0x90, 0xCD, 0, 0, 7, 0x01, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]);
}

Future writeFile01(Uint8List data) async {
await _send([0x90, 0x3D, 0, 0, 7 + data.length, 0x01, 0, 0, 0, data.length, 0, 0, ...data, 0]);
}

Future readFile01() async {
return await _send([0x90, 0xBD, 0, 0, 7, 0x01, 0, 0, 0, 32, 0, 0, 0]);
}

Uint8List keyZero() =>  Uint8List(16)..fillRange(0, 16, 0);

BlockCipher _initDes3(Uint8List key, Uint8List iv, {required bool decrypt}) {
final k24 = Uint8List.fromList([...key, ...key.sublist(0, 8)]);
return BlockCipher('DESede/CBC')
..init(!decrypt, ParametersWithIV(KeyParameter(k24), iv));
}

Uint8List _des3cbc(Uint8List data, {required bool encrypt}) {
final key = Uint8List.fromList([..._sk, ..._sk.sublist(0, 8)]);
final cipher = BlockCipher('DESede/CBC')
..init(encrypt, ParametersWithIV(KeyParameter(key), _iv));
final out = Uint8List(data.length);
for (int i = 0; i < data.length; i += 8) {
cipher.processBlock(data, i, out, i);
}
return out;
}

Uint8List _retailMac4(List msg) {
final key = Uint8List.fromList([..._sk, ..._sk.sublist(0, 8)]);
final cipher = BlockCipher('DESede/CBC')
..init(true, ParametersWithIV(KeyParameter(key), Uint8List(8)));
var buf = Uint8List.fromList(msg);
if (buf.length % 8 != 0) buf = Uint8List.fromList([...buf, ...List.filled(8 - (buf.length % 8), 0)]);
final out = Uint8List(buf.length);
for (int i = 0; i < buf.length; i += 8) {
cipher.processBlock(buf, i, out, i);
}
return Uint8List.fromList(out.sublist(out.length - 8, out.length - 4));
}

Uint8List _crc32(List data) {
int crc = 0xFFFFFFFF;
for (final b in data) {
crc ^= b;
for (int i = 0; i < 8; i++) {
crc = (crc & 1) != 0 ? (crc >> 1) ^ 0xEDB88320 : crc >> 1;
}
}
crc = ~crc;
return Uint8List.fromList([
crc & 0xFF,
(crc >> 8) & 0xFF,
(crc >> 16) & 0xFF,
(crc >> 24) & 0xFF,
]);
}

Future _send(List apdu) async {
print('APDU: ${_hex(apdu)}');
final r = await FlutterNfcKit.transceive(Uint8List.fromList(apdu));
print('Response: ${_hex(r)}');
if (r.length < 2 || r[r.length - 2] != 0x91 || r.last != 0x00) {
throw 'Card returned: ${_hex(r)}';
}
return r.sublist(0, r.length - 2);
}

String _hex(List b) => b.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');
}
< /code>
Hier sind meine Protokolle: < /p>
The Flutter DevTools debugger and profiler on Pixel 9 Pro XL is available at: http://127.0.0.1:9100?uri=http://127.0.0.1:35533/wcQn5hF5PLs=/
I/flutter ( 9430): Attempting AES authentication...
I/flutter ( 9430): APDU: 90 aa 00 00 01 00 00
I/flutter ( 9430): Response: 91 ae
I/flutter ( 9430): AES authentication failed: Card returned: 91 ae. Falling back to legacy 3DES...
I/flutter ( 9430): APDU: 90 0a 00 00 01 00 00
I/flutter ( 9430): Response: 4f 48 1e 6e bf b1 df ba 91 af

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post