Giter Club home page Giter Club logo

dmrtd's Introduction

Dart library for ICAO Machine Readable Travel Documents standard - Biometric Passport

LGPL v3 tests

DMRTD is dart implementation of ICAO 9303 standard. Library provide APIs to send commands to and read data from MRTD.

Key features

  • PACE & BAC session key establishment protocol
  • Reading all elementary files from MRTD, e.g.: EF.DG1, EF.DG2, EF.DG11, EF.DG12, EF.DG15 ...
    Note: most of files are not fully parsed yet.
  • Executing Active Authentication on MRTD (i.e.: sign arbitrary data with passport)
  • Basic implementation of ICC ISO7816-4 smart card standard
  • Implementation of ISO 9797 Algorithm 3 MAC and padding scheme

Library structure

dmrtd.dart - public passport API
extensions.dart - exposes library's dart extensions
internal.dart - exposes internal components of the library such as MrtdApi, ICC and crypto

Usage

  1. Include dmrtd library in your project's pubspec.yaml file:
dependencies:
  dmrtd:
    path: '<path_to_dmrtd_folder>'
  1. Run
flutter pub get

Example:
Note: See also example app

import 'package:dmrtd/dmrtd.dart';

try {
  final nfc = NfcProvider();
  await nfc.connect(iosAlertMessage: "Hold your iPhone near Passport");

  final passport = Passport(nfc);

  nfc.setIosAlertMessage("Reading EF.CardAccess ...");
  final cardAccess = await passport.readEfCardAccess();

  _nfc.setIosAlertMessage("Initiating session with PACE or BAC...");
  //set MrtdData
  mrtdData.isPACE = true; //initialize with PACE(set false if you want to do with DBA)
  mrtdData.isDBA = accessKey.PACE_REF_KEY_TAG == 0x01 ? true : false;

  if (isPace) {
    //PACE session
    await passport.startSessionPACE(accessKey, mrtdData.cardAccess!);
  } else {
    //BAC session
    await passport.startSession(accessKey as DBAKey);
  }

  nfc.setIosAlertMessage(formatProgressMsg("Reading EF.COM ...", 0));
  final efcom = await passport.readEfCOM();

  nfc.setIosAlertMessage(formatProgressMsg("Reading Data Groups ...", 20));
  EfDG1 dg1;
  if (efcom.dgTags.contains(EfDG1.TAG)) {
    dg1 = await passport.readEfDG1();
  }

  EfDG2 dg2;
  if (efcom.dgTags.contains(EfDG2.TAG)) {
    dg2 = await passport.readEfDG2();
  }

  EfDG14 dg14;
  if (efcom.dgTags.contains(EfDG14.TAG)) {
    dg14 = await passport.readEfDG14();
  }

  EfDG15 dg15;
  Uint8List sig;
  if (efcom.dgTags.contains(EfDG15.TAG)) {
    dg15 = await passport.readEfDG15();
    nfc.setIosAlertMessage(formatProgressMsg("Doing AA ...", 60));
    sig  = await passport.activeAuthenticate(Uint8List(8));
  }

  nfc.setIosAlertMessage(formatProgressMsg("Reading EF.SOD ...", 80));
  final sod = await passport.readEfSOD();
}
on Exception catch(e) {
  final se = e.toString().toLowerCase();
  String alertMsg = "An error has occurred while reading Passport!";
  if (e is PassportError) {
      if (se.contains("security status not satisfied")) {
        alertMsg = "Failed to initiate session with passport.\nCheck input data!";
    }
  }

  if (se.contains('timeout')){
    alertMsg = "Timeout while waiting for Passport tag";
  }
  else if (se.contains("tag was lost")) {
    alertMsg = "Tag was lost. Please try again!";
  }
  else if (se.contains("invalidated by user")) {
    alertMsg = "";
  }

  errorAlertMsg = alertMsg;
}
finally {
  if (errorAlertMsg?.isNotEmpty) {
    await _nfc.disconnect(iosErrorMessage: errorAlertMsg);
    if (!Platform.isIOS) {
    // Show error to the user
    }
  }
  else {
    await _nfc.disconnect(iosAlertMessage: formatProgressMsg("Finished", 100));
  }
}

Other documentation

License

This project is licensed under the terms of the GNU Lesser General Public License (LGPL) for open-source use and a Commercial License for proprietary use. See the LICENSE.LGPL and LICENSE.COMMERCIAL files for details.

dmrtd's People

Contributors

abdullahkaracabey avatar harrybawsac avatar nejc-skerjanc avatar smlu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

dmrtd's Issues

IOS Error The connection to service named com.apple.nfcd.service.corenfc

[CoreNFC] -[NFCHardwareManager areFeaturesSupported:outError:]:166 XPC Error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.nfcd.service.corenfc was invalidated from this process." UserInfo={NSDebugDescription=The connection to service named com.apple.nfcd.service.corenfc was invalidated from this process.}

Invalid date format

Screenshot (740)
Hello , first of all thanks for this awesome lib , im trying to scan a passport using the example provided in the dev branch , i keep getting an invalid date format Exception
This is the format i get using the datepicker

_dob = "10/28/1998";

_doe = "10/31/2028";

Apdu with usb

Hello
I would like to send an APDU to a device with usb connection and not with nfc. Is it possible with your lib ?
Thx

Parse data stored in dg7

From documentations I found online , it say mark or signature (digital version of hand written signature) are stored in dg7 data , I know it is optional in some documents , I'm trying to parse the imageData if its present just like in dg2

How can i read images from passport ?

Hi,

I am trying to read image data from passport. How can i take photos from passport with using dmrtd ? I try to take bytearray from dg2 and transform to image with using Image.memory(bytes) but it doesnt work. İt give wrong data error. İs it another data in dg2 other than faceimages ?

AESCipher decrypt error

Hi, I am getting an error when using this package on PACE-enabled passports.
The following shows the error logs:

I/flutter (22095): icc FINE: 2024-06-25 15:45:16.937965: Transceiving to ICC: C-APDU(CLA:10 INS:86 P1:00 P2:00 Le:256 Lc:2 Data:7c00)
I/flutter (22095): icc FINE: 2024-06-25 15:45:16.938715: Sending 8 byte(s) to ICC: data='10860000027c0000'
I/flutter (22095): icc FINE: 2024-06-25 15:45:17.109588: Received 38 byte(s) from ICC
I/flutter (22095): icc FINE: 2024-06-25 15:45:17.110085:  data='7c228020e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e39000'
I/flutter (22095): icc FINE: 2024-06-25 15:45:17.110480: Received response from ICC: sw=9000 data_len=36
I/flutter (22095): icc FINE: 2024-06-25 15:45:17.110747:  data=7c228020e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e3
I/flutter (22095): pace FINE: 2024-06-25 15:45:17.110950: Got PACE step 1 SUCCESSFUL response from ICC
I/flutter (22095): ResponseAPDUStep1Pace FINER: 2024-06-25 15:45:17.111158: ResponseAPDUStep1Pace data: 7c228020e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e3
I/flutter (22095): ResponseAPDUStep1Pace FINER: 2024-06-25 15:45:17.111744: Pace.step1; Response data contains dynamic authentication data
I/flutter (22095): ResponseAPDUStep1Pace FINER: 2024-06-25 15:45:17.111960: Nonce: e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e3
I/flutter (22095): pace FINE: 2024-06-25 15:45:17.112137: PACE.decryptNonce; Decrypting nonce ...
I/flutter (22095): pace FINER: 2024-06-25 15:45:17.112432: PACE.decryptNonce; Nonce: e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e3, Pace protocol: OIEPaceProtocol: 0.4.0.127.0.7.2.2.4.2.4, id-PACE-ECDH-GM-AES-CBC-CMAC-256, [0, 4, 0, 127, 0, 7, 2, 2, 4, 2, 4], CipherAlgorithm: CipherAlgorithm.AES, KEY_LENGTH: KEY_LENGTH.s256, TOKEN_AGREEMENT_ALGO: TOKEN_AGREEMENT_ALGO.ECDH, MAPPING_TYPE: MAPPING_TYPE.GM
I/flutter (22095): AccessKey.DBAKeys FINE: 2024-06-25 15:45:17.114200: Calculating K-pi key ...
I/flutter (22095): AccessKey.DBAKeys FINE: 2024-06-25 15:45:17.114393: Seed: d61e9ad73e4eab753c6e477188229e2c21c6a41e, Key length: KEY_LENGTH.s256, Cipher algorithm: CipherAlgorithm.AES
I/flutter (22095): pace FINER: 2024-06-25 15:45:17.116219: PACE.decryptNonce; K-pi: 4a14104c5d366f406ebdcdddb4473e8a14c714fe6aa9f8788acba36479cbe124
I/flutter (22095): pace FINE: 2024-06-25 15:45:17.116455: PACE.decryptNonce; Cipher algorithm: AES
I/flutter (22095): AESChiperSelector FINER: 2024-06-25 15:45:17.116663: AES chiper with 128-bit key size selected.
I/flutter (22095): AESCipher FINEST: 2024-06-25 15:45:17.116876: AESCipher.decrypt; data size: 32, data: e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e3
I/flutter (22095): AESCipher FINER: 2024-06-25 15:45:17.117092: AESCipher.decrypt; data: e99c8092a8c27b9f97a7d4ed2c5b1d318880c694208166623c0b7d57b31976e3, key size: 32, key: 4a14104c5d366f406ebdcdddb4473e8a14c714fe6aa9f8788acba36479cbe124
I/flutter (22095): AESCipher SEVERE: 2024-06-25 15:45:17.117352: AESCipher.decrypt; AES128 key length must be 128 bits.
I/flutter (22095): pace SEVERE: 2024-06-25 15:45:17.117689: PACE.decryptNonce; Failed: AESCipher.decrypt; AES128 key length must be 128 bits.
I/flutter (22095): pace SEVERE: 2024-06-25 15:45:17.117972: PACE(1); Failed: PACE.decryptNonce; Failed: AESCipher.decrypt; AES128 key length must be 128 bits.
I/flutter (22095): pace SEVERE: 2024-06-25 15:45:17.118253: PACE key establishment failed: PACE(1); Failed: PACE.decryptNonce; Failed: AESCipher.decrypt; AES128 key length must be 128 bits.
I/flutter (22095): mrtdeg.app SEVERE: 2024-06-25 15:45:17.118764: An exception was encountered while trying to read Passport: PACE key establishment failed: PACE(1); Failed: PACE.decryptNonce; Failed: AESCipher.decrypt; AES128 key length must be 128 bits.
I/flutter (22095): nfc.provider FINE: 2024-06-25 15:45:17.119230: Disconnecting

It works fine for BAC though

Support for PACE 2.0 authentication using CAN

Hi,

is there any further progress for supporting PACE authentication with CAN based access key?
Currently there is only BAC, which is slowly becoming deprecated and superseded by PACE.

Support

Hello, after cloning I cannot run the project, can you help me? Please..

Security status not satisfied

Here is my code to read passport data using NFC:

final nfc = NfcProvider();
try {
await nfc.connect(iosAlertMessage: "Hold your iPhone near Passport");
final passport = Passport(nfc);

  nfc.setIosAlertMessage("Reading EF.CardAccess...");
  final cardAccess = await passport.readEfCardAccess();

  nfc.setIosAlertMessage("Initiating session...");
  final bacKeySeed = DBAKeys(
      "AB6613787",
      DateTime(1998, DateTime.august, 17),
      DateTime(2027, DateTime.april, 21));
  await passport.startSession(bacKeySeed);

  nfc.setIosAlertMessage("Reading EF.COM...");
  final efcom = await passport.readEfCOM();

  nfc.setIosAlertMessage("Reading Data Groups...");
  EfDG1? dg1;
  if (efcom.dgTags.contains(EfDG1.TAG)) {
    dg1 = await passport.readEfDG1();
  }
  EfDG2 dg2;
  if (efcom.dgTags.contains(EfDG2.TAG)) {
    dg2 = await passport.readEfDG2();
  }
  // You can read other data groups similarly

  nfc.setIosAlertMessage("Reading EF.SOD...");
  final sod = await passport.readEfSOD();

  // You can print or display the data groups as you wish
  print(dg1?.mrz);
  // print(dg2.);
} catch (e) {
  print("as87das: $e");
  // Handle errors
} finally {
  await nfc.disconnect();
}

This line: final cardAccess = await passport.readEfCardAccess();
Gives this error in catch: Security status not satisfied

Read id card flutter desktop app

Hello, thanks for the great code ! The code works perfectly for me in android, I need to build a desktop app to read passport using external NFC reader. Which type should I buy please ? And how to do it ? Thanks in advance ❤️

Example doesn't build profile or release builds.

Was trying to build the example app. It works in debug mode, but when trying to run it in profile or release mode it shows the following error:

Command RuleScriptExecution failed with a nonzero exit code
    ld: framework not found Flutter
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

It seems like it is a consequence of the flutter_nfc_kit dependency, but not 100% sure.

Rapdu 6300 error when reading PACE-enabled Greek passport

Hi, I am getting the following error when reading PACE-enabled Greek passport:

PACE <ECDH> key establishment failed: PACE <ECDH> (4); Failed: ICC Error: General authentication template (step 4) failed sw=6300

I have narrowed it down to this function:

Future<Uint8List> generalAuthenticatePACEstep4({ required Uint8List data, int ne = 256, int cla = ISO7816_CLA.NO_SM }) async {

it seems the rapdu status is 6300 when it needs to be 9000 when reading in PACE mode.

This error only happens for the Greek passport. It succeeds when reading PACE-enabled Singapore passport.
I have checked the input fields such as the mrtdNumber, date of birth and date of expiry and they are correct.

Algerian 2024 cards error

Hello Sir !, thank you very much for the library, it was working very good with Algerian passports and Idcards, but I'm facing the next error with the new Idcards:

I/flutter (19080): passport FINE: 2024-08-05 16:26:15.734148: Reading EF.CardAccess
I/flutter (19080): passport FINE: 2024-08-05 16:26:15.740979: Selecting MF
I/flutter (19080): mrtd.api FINE: 2024-08-05 16:26:15.742924: Selecting root Master File
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.746479: Transceiving to ICC: C-APDU(CLA:00 INS:A4 P1:00 P2:00 Le:0 Lc:0 Data:null)
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.751509: Sending 4 byte(s) to ICC: data='00a40000'
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.795560: Received 2 byte(s) from ICC
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.797960: Received response from ICC: sw=6700 data_len=0
I/flutter (19080): mrtd.api WARNING: 2024-08-05 16:26:15.802688: Couldn't select MF by P1: 0, P2: 0 sw=sw=6700, re-trying to select MF with FileID=3F00
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.805214: Transceiving to ICC: C-APDU(CLA:00 INS:A4 P1:00 P2:00 Le:0 Lc:2 Data:3f00)
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.806180: Sending 7 byte(s) to ICC: data='00a40000023f00'
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.852395: Received 2 byte(s) from ICC
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.852691: Received response from ICC: sw=6700 data_len=0
I/flutter (19080): mrtd.api WARNING: 2024-08-05 16:26:15.853470: Couldn't select MF by P1=0, P2=0, FileID=3F00 sw=sw=6700, re-trying to select MF with P2=0x0C and FileID=3F00
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.854104: Transceiving to ICC: C-APDU(CLA:00 INS:A4 P1:00 P2:0C Le:0 Lc:2 Data:3f00)
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.854427: Sending 7 byte(s) to ICC: data='00a4000c023f00'
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.892469: Received 2 byte(s) from ICC
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.892794: Received response from ICC: sw=9000 data_len=0
I/flutter (19080): mrtd.api FINE: 2024-08-05 16:26:15.894335: Reading file sfi=0x1C
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.895624: Transceiving to ICC: C-APDU(CLA:00 INS:B0 P1:9C P2:00 Le:8 Lc:0 Data:null)
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.896093: Sending 5 byte(s) to ICC: data='00b09c0008'
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.948402: Received 2 byte(s) from ICC
I/flutter (19080): icc FINE: 2024-08-05 16:26:15.948822: Received response from ICC: sw=6282 data_len=0
I/flutter (19080): nfc.provider FINE: 2024-08-05 16:26:15.950810: Disconnecting
E/flutter (19080): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value
E/flutter (19080): #0 MrtdApi.readFileBySFI (package:dmrtd/src/proto/mrtd_api.dart:167:51)
E/flutter (19080):
E/flutter (19080): #1 Passport._exec (package:dmrtd/src/passport.dart:428:14)
E/flutter (19080):
E/flutter (19080): #2 Passport.readEfCardAccess (package:dmrtd/src/passport.dart:104:11)
E/flutter (19080):
E/flutter (19080): #3 _MrtdHomePageState._readMRTD (package:mrtdeg/main.dart:264:31)
E/flutter (19080):
E/flutter (19080):

this is my code:

// Created by Crt Vavros, copyright © 2022 ZeroPass. All rights reserved.
// ignore_for_file: prefer_adjacent_string_concatenation, prefer_interpolation_to_compose_strings

import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:async';
import 'dart:typed_data';
import 'package:image_picker/image_picker.dart';
import 'package:dmrtd/dmrtd.dart';
import 'package:dmrtd/extensions.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:toast/toast.dart';

class MrtdData {
EfCardAccess? cardAccess;
EfCardSecurity? cardSecurity;
EfCOM? com;
EfSOD? sod;
EfDG1? dg1;
EfDG2? dg2;
EfDG3? dg3;
EfDG4? dg4;
EfDG5? dg5;
EfDG6? dg6;
EfDG7? dg7;
EfDG8? dg8;
EfDG9? dg9;
EfDG10? dg10;
EfDG11? dg11;
EfDG12? dg12;
EfDG13? dg13;
EfDG14? dg14;
EfDG15? dg15;
EfDG16? dg16;
Uint8List? aaSig;
}

final Map<DgTag, String> dgTagToString = {
EfDG1.TAG: 'EF.DG1',
EfDG2.TAG: 'EF.DG2',
EfDG3.TAG: 'EF.DG3',
EfDG4.TAG: 'EF.DG4',
EfDG5.TAG: 'EF.DG5',
EfDG6.TAG: 'EF.DG6',
EfDG7.TAG: 'EF.DG7',
EfDG8.TAG: 'EF.DG8',
EfDG9.TAG: 'EF.DG9',
EfDG10.TAG: 'EF.DG10',
EfDG11.TAG: 'EF.DG11',
EfDG12.TAG: 'EF.DG12',
EfDG13.TAG: 'EF.DG13',
EfDG14.TAG: 'EF.DG14',
EfDG15.TAG: 'EF.DG15',
EfDG16.TAG: 'EF.DG16'
};

String formatEfCom(final EfCOM efCom) {
var str = "version: ${efCom.version}\n"
"unicode version: ${efCom.unicodeVersion}\n"
"DG tags:";

for (final t in efCom.dgTags) {
try {
str += " ${dgTagToString[t]!}";
} catch (e) {
str += " 0x${t.value.toRadixString(16)}";
}
}
return str;
}

String formatMRZ(final MRZ mrz) {
return "MRZ\n"
" version: ${mrz.version}\n" +
" doc code: ${mrz.documentCode}\n" +
" doc No.: ${mrz.documentNumber}\n" +
" country: ${mrz.country}\n" +
" nationality: ${mrz.nationality}\n" +
" name: ${mrz.firstName}\n" +
" surname: ${mrz.lastName}\n" +
" gender: ${mrz.gender}\n" +
" date of birth: ${DateFormat.yMd().format(mrz.dateOfBirth)}\n" +
" date of expiry: ${DateFormat.yMd().format(mrz.dateOfExpiry)}\n" +
" add. data: ${mrz.optionalData}\n" +
" add. data: ${mrz.optionalData2}";
}

String formatDG15(final EfDG15 dg15) {
var str = "EF.DG15:\n"
" AAPublicKey\n"
" type: ";

final rawSubPubKey = dg15.aaPublicKey.rawSubjectPublicKey();
if (dg15.aaPublicKey.type == AAPublicKeyType.RSA) {
final tvSubPubKey = TLV.fromBytes(rawSubPubKey);
var rawSeq = tvSubPubKey.value;
if (rawSeq[0] == 0x00) {
rawSeq = rawSeq.sublist(1);
}

final tvKeySeq = TLV.fromBytes(rawSeq);
final tvModule = TLV.decode(tvKeySeq.value);
final tvExp = TLV.decode(tvKeySeq.value.sublist(tvModule.encodedLen));

str += "RSA\n"
    "    exponent: ${tvExp.value.hex()}\n"
    "    modulus: ${tvModule.value.hex()}";

} else {
str += "EC\n SubjectPublicKey: ${rawSubPubKey.hex()}";
}
return str;
}

String formatProgressMsg(String message, int percentProgress) {
final p = (percentProgress / 20).round();
final full = "🟢 " * p;
final empty = "⚪️ " * (5 - p);
return message + "\n\n" + full + empty;
}

late SharedPreferences prefs;

void main() async {
WidgetsFlutterBinding.ensureInitialized();
prefs = await SharedPreferences.getInstance();
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) {
print(
'${record.loggerName} ${record.level.name}: ${record.time}: ${record.message}');
});
runApp(MrtdEgApp());
}

class MrtdEgApp extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return MaterialApp(localizationsDelegates: [
DefaultMaterialLocalizations.delegate,
DefaultCupertinoLocalizations.delegate,
DefaultWidgetsLocalizations.delegate,
], home: MrtdHomePage());
}
}

class MrtdHomePage extends StatefulWidget {
@OverRide
// ignore: library_private_types_in_public_api
_MrtdHomePageState createState() => _MrtdHomePageState();
}

class _MrtdHomePageState extends State {
var _alertMessage = "";
final _log = Logger("mrtdeg.app");
var _isNfcAvailable = false;
var _isReading = false;
final _mrzData = GlobalKey();

// mrz data
final _docNumber = TextEditingController(text: "411358813");
final _dob = TextEditingController(text: "10/18/1992"); // date of birth
final _doe = TextEditingController(text: "04/22/2034"); // date of doc expiry

MrtdData? _mrtdData;

final NfcProvider _nfc = NfcProvider();
// ignore: unused_field
late Timer _timerStateUpdater;
final _scrollController = ScrollController();

@OverRide
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);

_initPlatformState();

// Update platform state every 3 sec
_timerStateUpdater = Timer.periodic(Duration(seconds: 3), (Timer t) {
  _initPlatformState();
});

}

// Platform messages are asynchronous, so we initialize in an async method.
Future _initPlatformState() async {
bool isNfcAvailable;
try {
NfcStatus status = await NfcProvider.nfcStatus;
isNfcAvailable = status == NfcStatus.enabled;
} on PlatformException {
isNfcAvailable = false;
}

// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;

setState(() {
  _isNfcAvailable = isNfcAvailable;
});

}

DateTime? _getDOBDate() {
if (_dob.text.isEmpty) {
return null;
}
return DateFormat.yMd().parse(_dob.text);
}

DateTime? _getDOEDate() {
if (_doe.text.isEmpty) {
return null;
}
return DateFormat.yMd().parse(_doe.text);
}

Future<String?> _pickDate(BuildContext context, DateTime firstDate,
DateTime initDate, DateTime lastDate) async {
final locale = Localizations.localeOf(context);
final DateTime? picked = await showDatePicker(
context: context,
firstDate: firstDate,
initialDate: initDate,
lastDate: lastDate,
locale: locale);

if (picked != null) {
  return DateFormat.yMd().format(picked);
}
return null;

}

void _readMRTD() async {
try {
setState(() {
_mrtdData = null;
_alertMessage = "Waiting for Passport tag ...";
_isReading = true;
});

  await _nfc.connect(
      iosAlertMessage: "Hold your phone near Biometric Passport");
  final passport = Passport(_nfc);

  setState(() {
    _alertMessage = "Reading Passport ...";
  });

  _nfc.setIosAlertMessage("Trying to read EF.CardAccess ...");
  final mrtdData = MrtdData();

  try {
    mrtdData.cardAccess = await passport.readEfCardAccess();
  } on PassportError {
    //if (e.code != StatusWord.fileNotFound) rethrow;
  }

  _nfc.setIosAlertMessage("Trying to read EF.CardSecurity ...");

  try {
    mrtdData.cardSecurity = await passport.readEfCardSecurity();
  } on PassportError {
    //if (e.code != StatusWord.fileNotFound) rethrow;
  }

  _nfc.setIosAlertMessage("Initiating session ...");
  final bacKeySeed =
  DBAKey(_docNumber.text, _getDOBDate()!, _getDOEDate()!);
  await passport.startSession(bacKeySeed);

  _nfc.setIosAlertMessage(formatProgressMsg("Reading EF.COM ...", 0));
  mrtdData.com = await passport.readEfCOM();

  _nfc.setIosAlertMessage(formatProgressMsg("Reading Data Groups ...", 20));

  if (mrtdData.com!.dgTags.contains(EfDG1.TAG)) {
    mrtdData.dg1 = await passport.readEfDG1();
  }

  if (mrtdData.com!.dgTags.contains(EfDG2.TAG)) {
    mrtdData.dg2 = await passport.readEfDG2();
  }

  // To read DG3 and DG4 session has to be established with CVCA certificate (not supported).
  // if(mrtdData.com!.dgTags.contains(EfDG3.TAG)) {
  //   mrtdData.dg3 = await passport.readEfDG3();
  // }

  // if(mrtdData.com!.dgTags.contains(EfDG4.TAG)) {
  //   mrtdData.dg4 = await passport.readEfDG4();
  // }

  if (mrtdData.com!.dgTags.contains(EfDG5.TAG)) {
    mrtdData.dg5 = await passport.readEfDG5();
  }

  if (mrtdData.com!.dgTags.contains(EfDG6.TAG)) {
    mrtdData.dg6 = await passport.readEfDG6();
  }

  if (mrtdData.com!.dgTags.contains(EfDG7.TAG)) {
    mrtdData.dg7 = await passport.readEfDG7();
  }

  if (mrtdData.com!.dgTags.contains(EfDG8.TAG)) {
    mrtdData.dg8 = await passport.readEfDG8();
  }

  if (mrtdData.com!.dgTags.contains(EfDG9.TAG)) {
    mrtdData.dg9 = await passport.readEfDG9();
  }

  if (mrtdData.com!.dgTags.contains(EfDG10.TAG)) {
    mrtdData.dg10 = await passport.readEfDG10();
  }

  if (mrtdData.com!.dgTags.contains(EfDG11.TAG)) {
    mrtdData.dg11 = await passport.readEfDG11();
  }

  if (mrtdData.com!.dgTags.contains(EfDG12.TAG)) {
    mrtdData.dg12 = await passport.readEfDG12();
  }

  if (mrtdData.com!.dgTags.contains(EfDG13.TAG)) {
    mrtdData.dg13 = await passport.readEfDG13();
  }

  if (mrtdData.com!.dgTags.contains(EfDG14.TAG)) {
    mrtdData.dg14 = await passport.readEfDG14();
  }

  if (mrtdData.com!.dgTags.contains(EfDG15.TAG)) {
    mrtdData.dg15 = await passport.readEfDG15();
    _nfc.setIosAlertMessage(formatProgressMsg("Doing AA ...", 60));
    mrtdData.aaSig = await passport.activeAuthenticate(Uint8List(8));
  }

  if (mrtdData.com!.dgTags.contains(EfDG16.TAG)) {
    mrtdData.dg16 = await passport.readEfDG16();
  }

  _nfc.setIosAlertMessage(formatProgressMsg("Reading EF.SOD ...", 80));
  mrtdData.sod = await passport.readEfSOD();

  setState(() {
    _mrtdData = mrtdData;
  });

  setState(() {
    _alertMessage = "";
  });

  _scrollController.animateTo(300.0,
      duration: Duration(milliseconds: 500), curve: Curves.ease);
} on Exception catch (e) {
  final se = e.toString().toLowerCase();
  String alertMsg = "An error has occurred while reading Passport!";
  if (e is PassportError) {
    if (se.contains("security status not satisfied")) {
      alertMsg =
      "Failed to initiate session with passport.\nCheck input data!";
    }
    _log.error("PassportError: ${e.message}");
  } else {
    _log.error(
        "An exception was encountered while trying to read Passport: $e");
  }

  if (se.contains('timeout')) {
    alertMsg = "Timeout while waiting for Passport tag";
  } else if (se.contains("tag was lost")) {
    alertMsg = "Tag was lost. Please try again!";
  } else if (se.contains("invalidated by user")) {
    alertMsg = "";
  }

  setState(() {
    _alertMessage = alertMsg;
  });
} finally {
  if (_alertMessage.isNotEmpty) {
    await _nfc.disconnect(iosErrorMessage: _alertMessage);
  } else {
    await _nfc.disconnect(
        iosAlertMessage: formatProgressMsg("Finished", 100));
  }
  setState(() {
    _isReading = false;
  });
}

}

bool _disabledInput() {
return _isReading || !_isNfcAvailable;
}

Widget _makeMrtdDataWidget(
{required String header,
required String collapsedText,
required dataText}) {
return ExpandablePanel(
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToCollapse: true,
hasIcon: true,
iconColor: Colors.red,
),
header: Text(header),
collapsed: Text(collapsedText,
softWrap: true, maxLines: 2, overflow: TextOverflow.ellipsis),
expanded: Container(
padding: const EdgeInsets.all(18),
color: Color.fromARGB(255, 239, 239, 239),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextButton(
child: Text('Copy'),
onPressed: () =>
Clipboard.setData(ClipboardData(text: dataText)),
),
SelectableText(dataText, textAlign: TextAlign.left)
])));
}

List _mrtdDataWidgets() {
List list = [];
if (_mrtdData == null) return list;

if (_mrtdData!.cardAccess != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.CardAccess',
      collapsedText: '',
      dataText: _mrtdData!.cardAccess!.toBytes().hex()));
}

if (_mrtdData!.cardSecurity != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.CardSecurity',
      collapsedText: '',
      dataText: _mrtdData!.cardSecurity!.toBytes().hex()));
}

if (_mrtdData!.sod != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.SOD',
      collapsedText: '',
      dataText: _mrtdData!.sod!.toBytes().hex()));
}

if (_mrtdData!.com != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.COM',
      collapsedText: '',
      dataText: formatEfCom(_mrtdData!.com!)));
}

if (_mrtdData!.dg1 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG1',
      collapsedText: '',
      dataText: formatMRZ(_mrtdData!.dg1!.mrz)));
}

if (_mrtdData!.dg2 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG2',
      collapsedText: '',
      dataText: _mrtdData!.dg2!.toBytes().hex()));
}

if (_mrtdData!.dg3 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG3',
      collapsedText: '',
      dataText: _mrtdData!.dg3!.toBytes().hex()));
}

if (_mrtdData!.dg4 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG4',
      collapsedText: '',
      dataText: _mrtdData!.dg4!.toBytes().hex()));
}

if (_mrtdData!.dg5 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG5',
      collapsedText: '',
      dataText: _mrtdData!.dg5!.toBytes().hex()));
}

if (_mrtdData!.dg6 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG6',
      collapsedText: '',
      dataText: _mrtdData!.dg6!.toBytes().hex()));
}

if (_mrtdData!.dg7 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG7',
      collapsedText: '',
      dataText: _mrtdData!.dg7!.toBytes().hex()));
}

if (_mrtdData!.dg8 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG8',
      collapsedText: '',
      dataText: _mrtdData!.dg8!.toBytes().hex()));
}

if (_mrtdData!.dg9 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG9',
      collapsedText: '',
      dataText: _mrtdData!.dg9!.toBytes().hex()));
}

if (_mrtdData!.dg10 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG10',
      collapsedText: '',
      dataText: _mrtdData!.dg10!.toBytes().hex()));
}

if (_mrtdData!.dg11 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG11',
      collapsedText: '',
      dataText: _mrtdData!.dg11!.toBytes().hex()));
}

if (_mrtdData!.dg12 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG12',
      collapsedText: '',
      dataText: _mrtdData!.dg12!.toBytes().hex()));
}

if (_mrtdData!.dg13 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG13',
      collapsedText: '',
      dataText: _mrtdData!.dg13!.toBytes().hex()));
}

if (_mrtdData!.dg14 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG14',
      collapsedText: '',
      dataText: _mrtdData!.dg14!.toBytes().hex()));
}

if (_mrtdData!.dg15 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG15',
      collapsedText: '',
      dataText: _mrtdData!.dg15!.toBytes().hex()));
}

if (_mrtdData!.aaSig != null) {
  list.add(_makeMrtdDataWidget(
      header: 'Active Authentication signature',
      collapsedText: '',
      dataText: _mrtdData!.aaSig!.hex()));
}

if (_mrtdData!.dg16 != null) {
  list.add(_makeMrtdDataWidget(
      header: 'EF.DG16',
      collapsedText: '',
      dataText: _mrtdData!.dg16!.toBytes().hex()));
}

return list;

}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,

    /*iosContentPadding: false,
iosContentBottomPadding: false,*/
    body: Material(
        child: SafeArea(
            child: Padding(
                padding: EdgeInsets.all(8.0),
                child: SingleChildScrollView(
                    controller: _scrollController,
                    child: Column(
                        crossAxisAlignment: CrossAxisAlignment.stretch,
                        children: <Widget>[
                          SizedBox(height: 20),
                          Row(children: <Widget>[
                            Text('NFC available:',
                                style: TextStyle(
                                    fontSize: 18.0,
                                    fontWeight: FontWeight.bold)),
                            SizedBox(width: 4),
                            Text(_isNfcAvailable ? "Yes" : "No",
                                style: TextStyle(fontSize: 18.0))
                          ]),
                          SizedBox(height: 40),
                          Padding(
                              padding: EdgeInsets.symmetric(
                                  vertical: 8.0, horizontal: 30.0),
                              child: Form(
                                key: _mrzData,
                                child: Column(
                                  crossAxisAlignment:
                                  CrossAxisAlignment.start,
                                  children: <Widget>[
                                    TextFormField(
                                      enabled: !_disabledInput(),
                                      controller: _docNumber,
                                      decoration: const InputDecoration(
                                          border: OutlineInputBorder(),
                                          labelText: 'Passport number',
                                          fillColor: Colors.white),
                                      inputFormatters: <TextInputFormatter>[
                                        FilteringTextInputFormatter.allow(
                                            RegExp(r'[A-Z0-9]+')),
                                        LengthLimitingTextInputFormatter(14)
                                      ],
                                      textInputAction: TextInputAction.done,
                                      textCapitalization:
                                      TextCapitalization.characters,
                                      autofocus: true,
                                      validator: (value) {
                                        if (value?.isEmpty ?? false) {
                                          return 'Please enter passport number';
                                        }
                                        return null;
                                      },
                                    ),
                                    SizedBox(height: 12),
                                    TextFormField(
                                        enabled: !_disabledInput(),
                                        controller: _dob,
                                        decoration: const InputDecoration(
                                            border: OutlineInputBorder(),
                                            labelText: 'Date of Birth',
                                            fillColor: Colors.white),
                                        autofocus: false,
                                        validator: (value) {
                                          if (value?.isEmpty ?? false) {
                                            return 'Please select Date of Birth';
                                          }
                                          return null;
                                        },
                                        onTap: () async {
                                          FocusScope.of(context)
                                              .requestFocus(FocusNode());
                                          // Can pick date which dates 15 years back or more
                                          final now = DateTime.now();
                                          final firstDate = DateTime(
                                              now.year - 90,
                                              now.month,
                                              now.day);
                                          final lastDate = DateTime(
                                              now.year - 15,
                                              now.month,
                                              now.day);
                                          final initDate = _getDOBDate();
                                          final date = await _pickDate(
                                              context,
                                              firstDate,
                                              initDate ?? lastDate,
                                              lastDate);

                                          FocusScope.of(context)
                                              .requestFocus(FocusNode());
                                          if (date != null) {
                                            _dob.text = date;
                                          }
                                        }),
                                    SizedBox(height: 12),
                                    TextFormField(
                                        enabled: !_disabledInput(),
                                        controller: _doe,
                                        decoration: const InputDecoration(
                                            border: OutlineInputBorder(),
                                            labelText: 'Date of Expiry',
                                            fillColor: Colors.white),
                                        autofocus: false,
                                        validator: (value) {
                                          if (value?.isEmpty ?? false) {
                                            return 'Please select Date of Expiry';
                                          }
                                          return null;
                                        },
                                        onTap: () async {
                                          FocusScope.of(context)
                                              .requestFocus(FocusNode());
                                          // Can pick date from tomorrow and up to 10 years
                                          final now = DateTime.now();
                                          final firstDate = DateTime(
                                              now.year,
                                              now.month,
                                              now.day + 1);
                                          final lastDate = DateTime(
                                              now.year + 10,
                                              now.month + 6,
                                              now.day);
                                          final initDate = _getDOEDate();
                                          final date = await _pickDate(
                                              context,
                                              firstDate,
                                              initDate ?? firstDate,
                                              lastDate);

                                          FocusScope.of(context)
                                              .requestFocus(FocusNode());
                                          if (date != null) {
                                            _doe.text = date;
                                          }
                                        })
                                  ],
                                ),
                              )),
                          SizedBox(height: 20),
                          TextButton(
                            // btn Read MRTD
                            onPressed: _disabledInput() ||
                                !_mrzData.currentState!.validate()
                                ? null
                                : _readMRTD,
                            child: Text(_isReading
                                ? 'Reading ...'
                                : 'Read Passport'),
                          ),
                          SizedBox(height: 4),
                          Text(_alertMessage,
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                  fontSize: 15.0,
                                  fontWeight: FontWeight.bold)),
                          SizedBox(height: 15),
                          Padding(
                            padding: EdgeInsets.all(8.0),
                            child: Column(
                                crossAxisAlignment:
                                CrossAxisAlignment.start,
                                children: <Widget>[
                                  Text(
                                      _mrtdData != null
                                          ? "Passport Data:"
                                          : "",
                                      textAlign: TextAlign.center,
                                      style: TextStyle(
                                          fontSize: 15.0,
                                          fontWeight: FontWeight.bold)),
                                  Padding(
                                      padding: EdgeInsets.only(
                                          left: 16.0,
                                          top: 8.0,
                                          bottom: 8.0),
                                      child: Column(
                                          crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                          children: _mrtdDataWidgets()))
                                ]),
                          ),
                        ]))))));

Padding _buildForm(BuildContext context) {
  return Padding(
      padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 30.0),
      child: Form(
        key: _mrzData,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            TextFormField(
              enabled: !_disabledInput(),
              controller: _docNumber,
              decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: 'Passport number',
                  fillColor: Colors.white),
              inputFormatters: <TextInputFormatter>[
                FilteringTextInputFormatter.allow(RegExp(r'[A-Z0-9]+')),
                LengthLimitingTextInputFormatter(14)
              ],
              textInputAction: TextInputAction.done,
              textCapitalization: TextCapitalization.characters,
              autofocus: true,
              validator: (value) {
                if (value?.isEmpty ?? false) {
                  return 'Please enter passport number';
                }
                return null;
              },
            ),
            SizedBox(height: 12),
            TextFormField(
                enabled: !_disabledInput(),
                controller: _dob,
                decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Date of Birth',
                    fillColor: Colors.white),
                autofocus: false,
                validator: (value) {
                  if (value?.isEmpty ?? false) {
                    return 'Please select Date of Birth';
                  }
                  return null;
                },
                onTap: () async {
                  FocusScope.of(context).requestFocus(FocusNode());
                  // Can pick date which dates 15 years back or more
                  final now = DateTime.now();
                  final firstDate =
                  DateTime(now.year - 90, now.month, now.day);
                  final lastDate =
                  DateTime(now.year - 15, now.month, now.day);
                  final initDate = _getDOBDate();
                  final date = await _pickDate(
                      context, firstDate, initDate ?? lastDate, lastDate);

                  FocusScope.of(context).requestFocus(FocusNode());
                  if (date != null) {
                    _dob.text = date;
                  }
                }),
            SizedBox(height: 12),
            TextFormField(
                enabled: !_disabledInput(),
                controller: _doe,
                decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Date of Expiry',
                    fillColor: Colors.white),
                autofocus: false,
                validator: (value) {
                  if (value?.isEmpty ?? false) {
                    return 'Please select Date of Expiry';
                  }
                  return null;
                },
                onTap: () async {
                  FocusScope.of(context).requestFocus(FocusNode());
                  // Can pick date from tomorrow and up to 10 years
                  final now = DateTime.now();
                  final firstDate =
                  DateTime(now.year, now.month, now.day + 1);
                  final lastDate =
                  DateTime(now.year + 10, now.month + 6, now.day);
                  final initDate = _getDOEDate();
                  final date = await _pickDate(
                      context, firstDate, initDate ?? firstDate, lastDate);

                  FocusScope.of(context).requestFocus(FocusNode());
                  if (date != null) {
                    _doe.text = date;
                  }
                })
          ],
        ),
      ));
}

}
}

I really appreciate your help !!

convert read data

I read data with project (EFSOD,EFCOM,EF.DG1 ....) but I can't convert them to string.. can you help me ?

for example :
Hex : 6c1f5c025f195f1918c4b0c387c4b0c59e4c4552c4b02042414b414e4c49c49e49 converted
Text : l�\�_�_��İ�İ�LERİ BAKANLI�I

Conditions of use not satisfied

Hi, I have successfully read the contents of a Singapore passport using both BAC and PACE.
However, when I try reading a Greek passport, it fails with the following error:

D/DeferrableSurface(32256): use count-1,  useCount=0 closed=true androidx.camera.core.SurfaceRequest$2@5bd1d54
D/DeferrableSurface(32256): Surface no longer in use[total_surfaces=3, used_surfaces=2](androidx.camera.core.SurfaceRequest$2@5bd1d54}
W/CameraDevice-JV-0(32256): Device error received, code 5, frame number 167, request ID 0, subseq ID 0
D/DeferrableSurface(32256): Surface terminated[total_surfaces=2, used_surfaces=2](androidx.camera.core.SurfaceRequest$2@5bd1d54}
W/CameraDevice-JV-0(32256): Device error received, code 4, frame number 168, request ID 0, subseq ID 0
W/CameraDevice-JV-0(32256): Device error received, code 5, frame number 168, request ID 0, subseq ID 0
W/CameraDevice-JV-0(32256): Device error received, code 5, frame number 168, request ID 0, subseq ID 0
D/DeferrableSurface(32256): use count-1,  useCount=0 closed=true androidx.camera.core.impl.ImmediateSurface@c382f3e
D/DeferrableSurface(32256): Surface no longer in use[total_surfaces=2, used_surfaces=1](androidx.camera.core.impl.ImmediateSurface@c382f3e}
D/DeferrableSurface(32256): Surface terminated[total_surfaces=1, used_surfaces=1](androidx.camera.core.impl.ImmediateSurface@c382f3e}
D/DeferrableSurface(32256): use count-1,  useCount=0 closed=true androidx.camera.core.impl.ImmediateSurface@504014a
D/DeferrableSurface(32256): Surface no longer in use[total_surfaces=1, used_surfaces=0](androidx.camera.core.impl.ImmediateSurface@504014a}
D/DeferrableSurface(32256): Surface terminated[total_surfaces=0, used_surfaces=0](androidx.camera.core.impl.ImmediateSurface@504014a}
D/Camera2CameraImpl(32256): {Camera@e755f2a[id=0]} CameraDevice.onClosed()
D/Camera2CameraImpl(32256): {Camera@e755f2a[id=0]} Transitioning camera internal state: CLOSING --> INITIALIZED
D/CameraStateRegistry(32256): Recalculating open cameras:
D/CameraStateRegistry(32256): Camera                                       State                 
D/CameraStateRegistry(32256): -------------------------------------------------------------------
D/CameraStateRegistry(32256): Camera@684dccd[id=1]                         UNKNOWN               
D/CameraStateRegistry(32256): Camera@e755f2a[id=0]                         CLOSED                
D/CameraStateRegistry(32256): -------------------------------------------------------------------
D/CameraStateRegistry(32256): Open count: 0 (Max allowed: 1)
D/CameraStateMachine(32256): New public camera state CameraState{type=CLOSED, error=null} from CLOSED and null
D/CameraStateMachine(32256): Publishing new public camera state CameraState{type=CLOSED, error=null}
W/BpBinder(32256): Slow Binder: BpBinder transact took 3582 ms, interface=android.nfc.INfcTag, code=6 oneway=false
W/BpBinder(32256): Slow Binder: BpBinder transact took 259 ms, interface=android.nfc.INfcTag, code=6 oneway=false
I/flutter (32256): PassportError: Conditions of use not satisfied

Does not work for German passport

Hi and thanks for this project!

Unfortunately, it does not work for German passports. I ran the code, it detects the chip, but then I get an error.
I assume they use PACE and not BAC anymore (even though I think they should be backwards compatible), or am I missing something?

Tag response error / no response when reading DG2 on iOS

When we read the DG2, connection is lost even if the document is correctly positioned on the phone (only iOS).
The error is the following:
[CoreNFC] -[NFCTagReaderSession transceive:tagUpdate:error:]:879 Error Domain=NFCError Code=102 "Tag response error / no response" UserInfo={NSLocalizedDescription=Tag response error / no response, NSUnderlyingError=0x280bc6d30 {Error Domain=nfcd Code=29 "Tag Error" UserInfo={NSLocalizedDescription=Tag Error, NSUnderlyingError=0x280bc7540 {Error Domain=com.apple.nfstack Code=20 "No response from tag" UserInfo={NSLocalizedDescription=No response from tag}}}}}

I tested on iPhone 12, 13, 14 with iOS 16.
I also tested on iPhone X and XR and everything's working fine.

Error: The method 'PlatformButton' isn't defined for the class

I get the following error. How do I fix it?

_lib/main.dart:563:29: Error: The method 'PlatformButton' isn't defined for the class '_MrtdHomePageState'.

  • 'MrtdHomePageState' is from 'package:nfc_passport_3/main.dart' ('lib/main.dart').
    Try correcting the name to the name of an existing method, or defining a method named 'PlatformButton'.
    PlatformButton( // btn Read MRTD
    ^^^^^^^^^^^^^^

Thanks!

An exception was encountered while trying to read Passport: FormatException: Invalid number (at character 1)

I am receiving the following error log when reading a passport. It works with other apps so I assume that it is not an issue with the passport I am using. What could this issue be related to?

Not the full log:

flutter: icc FINE: 2022-02-17 14:18:29.292117: Transceiving to ICC: C-APDU(CLA:00 INS:B0 P1:00 P2:08 Le:256 Lc:0 Data:null)
flutter: mrtd.sm FINE: 2022-02-17 14:18:29.292228: Protecting APDU
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.292453:   header=00b00008
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.292623:   data=null
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.292725:   Le=256
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.292887: masked APDU header=0cb00008
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.293006: Generated data DO=
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.293149: Generated data DO97=970100
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.293304: Generated M=0cb0000880000000970100
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.293693: Generated N=4af8b0801b9fe1eb0cb00008800000009701008000000000
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.293901:   used SSC=4af8b0801b9fe1eb
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.295125: Calculated CC=c2a335e25877dfdd
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.295230: Generated data DO8E=8e08c2a335e25877dfdd
flutter: icc FINE: 2022-02-17 14:18:29.295355: Sending 19 byte(s) to ICC: data='0cb000080d9701008e08c2a335e25877dfdd00'
flutter: icc FINE: 2022-02-17 14:18:29.324454: Received 107 byte(s) from ICC
flutter: icc FINE: 2022-02-17 14:18:29.324789:  data='<..redacted...>93963ad39000'
flutter: mrtd.sm FINE: 2022-02-17 14:18:29.325054: Unprotecting RAPDU: sw=9000 data=<..redacted...>693963ad3
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.329571: Generated K=<..redacted...>2900080
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.330052:   used SSC=4af8b0801b9fe1ec
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.330334: APDU CC=a8a7551693963ad3
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.330453: Calculated CC=a8a7551693963ad3
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.330644: Decrypting data=<..redacted...>2ef5c2
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.337735: Decrypted data=<..redacted...>3c38800000
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.337933: Decrypted data is padded: true
flutter: mrtd.sm FINER: 2022-02-17 14:18:29.338026: Decrypted and upadded data=<..redacted...>3c38
flutter: icc FINE: 2022-02-17 14:18:29.338224: Received response from ICC: sw=9000 data_len=85
flutter: icc FINE: 2022-02-17 14:18:29.338420:  data=<..redacted...>3c3c38
flutter: mrtdeg.app SEVERE: 2022-02-17 14:18:29.339651: An exception was encountered while trying to read Passport: FormatException: Invalid number (at character 1)


^
flutter: nfc.provider FINE: 2022-02-17 14:18:29.340014: Disconnecting

CommandAPDU status 6988

Hi, I am getting on some documents CommandAPDU status 6988 instead of 9000.

Do you know about this error?

It dose not work with me for syrian passport

I've made sure from passport number DOB and expiration date, but I still haven’t succeed
in this code
final rapdu = await _transceive(
CommandAPDU(cla: cla, ins: ISO7816_INS.EXTERNAL_AUTHENTICATE, p1: 0x00, p2: 0x00, data: data, ne: ne)
);
if(rapdu.status != StatusWord.success) {
throw ICCError("External authenticate failed", rapdu.status, rapdu.data);
}

Always the status != StatusWord.success

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.