From cb028e345d3bb39eb67a6251698b29f42b6cbf23 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Tue, 7 Mar 2023 21:06:01 +0700 Subject: [PATCH] parse basic user data --- app/src/main/cpp/api.cpp | 78 ++++++++++++++++++++++++++++++++++++++++ app/src/main/cpp/api.h | 25 ++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/app/src/main/cpp/api.cpp b/app/src/main/cpp/api.cpp index 2512a84..1913883 100644 --- a/app/src/main/cpp/api.cpp +++ b/app/src/main/cpp/api.cpp @@ -377,6 +377,77 @@ bytes Connector::readBinary(size_t offset, size_t length) { #define VERBOSE_LOGGING VERBOSE_LOGGING_OFF } +void Connector::set_user_data(bytes mrz) { + if (mrz.size() != 90) { + throw "MRZ data must be 90 bytes"; + } + std::string line1(mrz.begin(), mrz.begin() + 30); + std::string line2(mrz.begin() + 30, mrz.begin() + 60); + std::string line3(mrz.begin() + 60, mrz.end()); + + std::string hash1 = line2.substr(line2.size()-1); + std::string data1 = line1.substr(5) + line2.substr(0, 7) + line2.substr(8, 7) + line2.substr(18, 11); + // assert(check_digit(data1) == std::stoi(hash1)); + + std::smatch match1; + std::regex_match(line1, match1, std::regex("ID(\\w{3})(\\d{9})(\\d)([\\w\\d<]{15})")); + passport.country = match1[1]; + passport.documentNumber = match1[2]; + std::string hash_id = match1[3], optional_line1 = match1[4]; +// assert(check_digit(id) == std::stoi(hash_id)); + + std::smatch match2; + std::regex_match(line2, match2, std::regex("(\\d{2})(\\d{2})(\\d{2})(\\d)([MF])(\\d{2})(\\d{2})(\\d{2})(\\d)(\\w{3})([\\w\\d<]{11})(\\d)")); + std::string birth_year = match2[1], birth_month = match2[2], birth_day = match2[3], hash_birth = match2[4]; + std::string expire_year = match2[6], expire_month = match2[7], expire_day = match2[8], hash_expire = match2[9]; + std::string optional_line2 = match2[11], hash_line2 = match2[12]; + + passport.nationality = match2[10]; + passport.gender = match2[5]; +// assert(check_digit(birth_year+birth_month+birth_day) == std::stoi(hash_birth)); +// assert(check_digit(expire_year+expire_month+expire_day) == std::stoi(hash_expire)); + + tm birth_tm = {0}, expire_tm = {0}; + birth_tm.tm_year = std::stoi(birth_year) + 100; + if (birth_tm.tm_year > (2023 - 1900)) { + birth_tm.tm_year -= 100; + } + birth_tm.tm_mon = std::stoi(birth_month) - 1; + birth_tm.tm_mday = std::stoi(birth_day); + + expire_tm.tm_year = std::stoi(expire_year) + 100; + expire_tm.tm_mon = std::stoi(expire_month) - 1; + expire_tm.tm_mday = std::stoi(expire_day); + + passport.birthDate = mktime(&birth_tm); + passport.expiryDate = mktime(&expire_tm); + + // trim ending < + line3.erase(std::find_if(line3.rbegin(), line3.rend(), [](unsigned char ch) { + return ch != '<'; + }).base(), line3.end()); + + auto nameparser = std::istringstream(line3); + std::string familyname; + std::getline(nameparser, familyname, '<'); + nameparser.get(); + + std::vector name_components; + for (std::string tmp; std::getline(nameparser, tmp, '<'); ) { + name_components.push_back(tmp); + } +} + +void Connector::set_user_picture(bytes dg2) { + auto pattern1 = bytes{0xFF, 0xD8, 0xFF, 0xE0}; + auto pattern2 = bytes{0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50}; + auto im_start = std::search(dg2.begin(), dg2.end(), pattern1.begin(), pattern1.end()); + if (im_start == dg2.end()) { + im_start = std::search(dg2.begin(), dg2.end(), pattern2.begin(), pattern2.end()); + } + passport.portrait = bytes(dg2.begin() + std::distance(dg2.begin(), im_start), dg2.end()); +} + void Connector::readEFCOM() { auto content = readFileBySFI(EFCOM_SFI); LOGI("FILE COM size %d", content.size()); @@ -389,6 +460,12 @@ void Connector::readEFDG1() { LOGI("FILE DG1 size %d", content.size()); logBytes("FILE DG1 sha256 %s", digest); calculatedDigests[1] = digest; + + // skip 2 bytes application data + // skip 2 bytes tag 5f1f + // skip 1 byte length + content.erase(content.begin(), content.begin() + 5); + set_user_data(content); } void Connector::readEFDG2() { auto content = readFileBySFI(EFDG2_SFI); @@ -396,6 +473,7 @@ void Connector::readEFDG2() { SHA256(content.data(), content.size(), digest.data()); LOGI("FILE DG2 size %d", content.size()); logBytes("FILE DG2 sha256 %s", digest); + set_user_picture(content); calculatedDigests[2] = digest; } void Connector::readEFDG13() { diff --git a/app/src/main/cpp/api.h b/app/src/main/cpp/api.h index 1c5d420..05870c0 100644 --- a/app/src/main/cpp/api.h +++ b/app/src/main/cpp/api.h @@ -12,6 +12,19 @@ #include "utils.h" #include "des.h" +struct PassportData { + std::string country; + std::string documentNumber; + std::string gender; + std::string nationality; + + std::string familyName; + std::vector nameComponents; + + time_t birthDate; + time_t expiryDate; + bytes portrait; +}; class TLV { public: @@ -230,9 +243,12 @@ private: bytes readFileBySFI(int sfi); bytes readBinary(size_t offset, size_t length); + void set_user_data(bytes data); + void set_user_picture(bytes data); std::unordered_map calculatedDigests; + // chip's public key bytes dg15; public: @@ -241,7 +257,14 @@ public: int readAheadLength = 8; - Connector(transceive_type transceive) : transceive(transceive) {} + std::string passcode; + +public: + bool ready = false; + + PassportData passport; + + Connector(transceive_type transceive, std::string passcode) : transceive(transceive), passcode(passcode) {} bool selectDf1(); void initBAC();