flutter_cccd_vn 2.0.1
flutter_cccd_vn: ^2.0.1 copied to clipboard
ICAO Doc 9303 MRTD (biometric passport) Dart library with a Vietnamese CCCD (căn cước công dân) NFC reading adapter — BAC/PACE, OCR-driven credentials, and a typed CCCD data/verification API.
flutter_cccd_vn — ICAO 9303 MRTD library with a Vietnamese CCCD (căn cước công dân) NFC adapter #
🇻🇳 Đọc bằng tiếng Việt
flutter_cccd_vn is a fork of ZeroPass/dmrtd,
a Dart implementation of the ICAO 9303
standard for biometric passports (MRTD), with a Vietnamese CCCD (căn cước
công dân) NFC reading adapter built on top of the same session/secure
messaging layer.
Key features #
Core ICAO 9303 / MRTD
- PACE & BAC session key establishment protocol
- Reading all elementary files from MRTD, e.g.: EF.DG1, EF.DG2, EF.DG11, EF.DG12, EF.DG15 ... (most files are not fully parsed yet)
- Executing
Active Authenticationon MRTD (i.e. sign arbitrary data with the passport) - Basic implementation of ICC ISO7816-4 smart card standard
- Implementation of ISO 9797 Algorithm 3 MAC and padding scheme
CCCD Việt Nam adapter
CccdReader: typed, retrying reader with classified errors (NFC disabled, timeout, tag lost, cancellation, connection, authentication, parse, integrity, busy)CccdCan(PACE via the 6-digit CAN) andCccdMrz(BAC via document number + date of birth + date of expiry — no CAN needed when those three fields are available, e.g. from OCR)CccdReadProgresscallback reporting real per-EF progress (document number → EF.COM → portrait → …), not a fake animationCccdOcrParser: Vietnamese-label OCR parsing for both the 2021 "CCCD gắn chip" and the 2024 "Căn cước" card layouts, with a checksum-validated MRZ fast pathCccdVerificationResult/CccdFaceMatchResult: pure-Dart contracts to compare NFC chip data, OCR text and an on-device face match
Library structure #
dmrtd.dart — public passport (MRTD) API
cccd_vietnam.dart — public CCCD Việt Nam API (CccdReader, CccdCan,
CccdMrz, CccdOcrParser, CccdVerificationResult, ...)
extensions.dart — exposes the library's Dart extensions
internal.dart — exposes internal components such as MrtdApi, ICC and crypto
Installation #
dependencies:
flutter_cccd_vn: ^2.0.0
or, from a local checkout:
dependencies:
flutter_cccd_vn:
path: '<path_to_flutter_cccd_vn_folder>'
Then:
flutter pub get
Quick start — CCCD Việt Nam #
Note: see also the example app for a full capture → OCR → NFC scan flow.
import 'package:flutter_cccd_vn/cccd_vietnam.dart';
final nfc = NfcProvider();
final reader = CccdReader(
transport: nfc,
protocol: IcaoCccdProtocol(),
operationTimeout: const Duration(seconds: 30),
maxRetries: 1,
);
await reader.connect();
// BAC via MRZ: no CAN required. documentNumber is the chip's ICAO
// document number field — the 9 digits of the 12-digit số định danh
// *without* its 3-digit province-code prefix.
final credential = CccdMrz(
documentNumber: '099888777',
dateOfBirth: DateTime(1995, 3, 15),
dateOfExpiry: DateTime(2038, 5, 15),
);
final data = await reader.read(
credential,
onProgress: (completed, total, stage) => print('$stage ($completed/$total)'),
);
await reader.disconnect();
print(data.documentNumber);
print(data.fullName);
To open the chip with the 6-digit CAN (PACE) instead of MRZ/BAC:
final data = await reader.read(CccdCan('123456'));
For a faster identity-only read, skip the optional files:
protocol: IcaoCccdProtocol(
includePortrait: false,
includeDg13: false,
),
Notes
- The adapter reads DG1 and optionally DG2/DG13 according to EF.COM. EAC/DG3/DG4 and full real-card compatibility still require physical-card validation and terminal credentials.
- Do not log CAN values, MRZ values or card payloads.
- Retries apply only to completed transient connection failures; a timeout
cannot be safely retried because Dart cannot cancel an in-flight NFC
Future. After a timeout the reader is poisoned: calldisconnect()for cleanup and create a newCccdReaderbefore retrying. Tag-lost and user-cancelled operations require a new user interaction. - The chip's MRZ document number is ICAO's 9-digit short form; when
comparing it against a 12-digit số định danh read via OCR, compare the
overlapping 9-digit suffix (
CccdVerificationResult.documentNumberMatchesalready does this for you).
NFC platform setup #
Android: the example already declares the NFC permission and hardware
support in example/android/app/src/main/AndroidManifest.xml.
iOS: enable the Near Field Communication Tag Reader Session Formats
capability, add NFCReaderUsageDescription to Info.plist, and add the
ISO7816 reader entitlement required by the app's provisioning profile.
This repository does not contain an example/ios target.
Local CCCD capture, OCR and face verification (example app) #
The example app uses camera, ML Kit text recognition, ML Kit face
detection and face_verification 0.3.8 to keep capture, OCR and FaceNet
comparison on-device. The root package only exports the pure Dart
contracts: CccdOcrParser, CccdFaceMatchResult and
CccdVerificationResult.
The local face score is a similarity signal, not liveness detection or
legal identity proof. CccdVerificationResult reports consistency, not
identity verification — calibrate the threshold with real devices and
lighting before production. The app deletes temporary images and the
temporary face template after each attempt and does not log OCR,
portrait, selfie or embeddings. face_verification may emit its own
internal debug score/ID logs; production deployments requiring a strict
biometric log policy should use a fork/configuration with those logs
disabled.
The example flow is Android-only (no example/ios host target). An iOS
consuming app must add NSCameraUsageDescription, NFC ISO7816
entitlements and use iOS 15.5+ for the selected face stack. DG2 JPEG2000
is reported as invalidPortrait; only JPEG is passed to the matcher.
Run on a real Android device:
cd example
flutter pub get
flutter run
Open Xác minh CCCD gắn chip, capture both card sides, review the
OCR result, tap Bắt đầu quét NFC, then optionally capture a selfie for
face matching. The result is matched, rejected or needsReview — not
liveness or legal identity verification.
Quick start — Passport (MRTD) #
import 'package:flutter_cccd_vn/dmrtd.dart';
final nfc = NfcProvider();
try {
await nfc.connect(iosAlertMessage: 'Hold your phone near the passport');
final passport = Passport(nfc);
final cardAccess = await passport.readEfCardAccess();
// PACE (recommended when EF.CardAccess is present) or BAC:
final accessKey = DBAKey('L898902C3', DateTime(1974, 8, 12), DateTime(2012, 4, 15));
if (cardAccess.isPaceInfoSet) {
await passport.startSessionPACE(accessKey, cardAccess);
} else {
await passport.startSession(accessKey);
}
final com = await passport.readEfCOM();
if (com.dgTags.contains(EfDG1.TAG)) {
final dg1 = await passport.readEfDG1();
print(dg1.mrz.documentNumber);
}
if (com.dgTags.contains(EfDG2.TAG)) {
final dg2 = await passport.readEfDG2();
}
await nfc.disconnect();
} on PassportError catch (e) {
await nfc.disconnect(iosErrorMessage: e.message);
}
Other documentation #
- ICAO 9303 Specifications Common to all MRTDs
- ICAO 9303 Specifications for Machine Readable Passports (MRPs) and other TD3 Size MRTDs
- ICAO 9303 eMRTD logical data structure
- ICAO 9303 Security mechanisms for MRTDs
License #
This project is dual-licensed: the GNU Lesser General Public License (LGPL-3.0) for open-source use, and a Commercial License for proprietary use. See LICENSE (or LICENSE.LGPL) and LICENSE.COMMERCIAL for details.
Original library ("dmrtd") © 2022 ZeroPass. This fork adds the CCCD Việt Nam adapter under the same LGPL-3.0 terms.