Esempio n. 1
0
def send(sm_object: SMObject, apdu: APDU) -> bytes:
    """
    Send APDU to the channel and return the data if there are no errors.
    """
    channel = sm_object.channel
    apdu_bytes = secure_messaging(sm_object, apdu)

    data, sw1, sw2 = channel.transmit(list(apdu_bytes))

    # success
    if [sw1, sw2] == [0x90, 0x00]:
        try:
            data = process_rapdu(sm_object, bytes(data))
        except ReplyAPDUError as ex:
            raise CardCommunicationError(
                "[-] Reply APDU MAC doesn't match!") from ex
        else:
            return data
    # signals that there is more data to read
    if sw1 == 0x61:
        print("[=] TAKE A LOOK! More data to read:", sw2)
        return data + send(sm_object,
                           APDU(b"\x00", b"\xC0", b"\x00", b"\x00",
                                Le=nb(sw2)))  # GET RESPONSE of sw2 bytes
    if sw1 == 0x6C:
        print("[=] TAKE A LOOK! Resending with Le:", sw2)
        return send(sm_object,
                    APDU(apdu.cla, apdu.ins, apdu.p1, apdu.p2,
                         Le=nb(sw2)))  # resend APDU with Le = sw2
    # probably error condition
    # channel.disconnect()
    print("[-] Card communication error occured.")
    print("Error: %02x %02x, sending APDU: %s" %
          (sw1, sw2, " ".join(["{:02x}".format(x)
                               for x in apdu_bytes]).upper()))
    print("Plain APDU: " + " ".join([
        "{:02x}".format(x)
        for x in (apdu.get_command_header() + (apdu.Lc or b"") +
                  (apdu.cdata or b"") + (apdu.Le or b""))
    ]).upper())
    raise CardCommunicationError(
        "Error: %02x %02x, sending APDU: %s" %
        (sw1, sw2, " ".join(["{:02x}".format(x) for x in apdu_bytes]).upper()))
Esempio n. 2
0
def establish_bac_session_keys(sm_object: SMObject, secret: bytes):
    """
    This function establishes session keys with the card
    Sets the necessary values of sm_object
    """
    # Calculate the SHA-1 hash of ‘MRZ_information’ and
    # take the most significant 16 bytes to form the basic access key seed
    ba_key_seed = hashlib.sha1(secret).digest()[:16]
    # Calculate the basic access keys (ba_key_enc and ba_key_mac)
    print("[+] Computing basic access keys...")
    ba_key_enc = compute_key(ba_key_seed, "enc", "3DES")
    ba_key_mac = compute_key(ba_key_seed, "mac", "3DES")

    ## AUTHENTICATION AND ESTABLISHMENT OF SESSION KEYS ##
    print("[+] Establishing session keys...")
    # exception caught in main program loop
    rnd_ic = send(sm_object,
                  APDU(b"\x00", b"\x84", b"\x00", b"\x00", Le=b"\x08"))

    rnd_ifd = urandom(8)
    k_ifd = urandom(16)
    s = rnd_ifd + rnd_ic + k_ifd
    e_cipher = DES3.new(ba_key_enc, DES3.MODE_CBC, bytes([0] * 8))
    e_ifd = e_cipher.encrypt(s)
    m_ifd = compute_mac(ba_key_mac, padding_method_2(e_ifd, 8), "DES")
    # Construct command data for EXTERNAL AUTHENTICATE
    cmd_data = e_ifd + m_ifd

    # exception caught in main program loop
    resp_data_enc = send(
        sm_object,
        APDU(b"\x00",
             b"\x82",
             b"\x00",
             b"\x00",
             Lc=nb(len(cmd_data)),
             cdata=cmd_data,
             Le=b"\x28"),
    )
    m_ic = compute_mac(ba_key_mac, padding_method_2(resp_data_enc[:-8], 8),
                       "DES")
    if m_ic != resp_data_enc[-8:]:
        raise SessionKeyEstablishmentError(
            "[-] Encrypted message MAC is not correct!")

    d_cipher = DES3.new(ba_key_enc, DES3.MODE_CBC, bytes([0] * 8))
    resp_data = d_cipher.decrypt(resp_data_enc[:-8])
    if resp_data[:8] != rnd_ic:
        raise SessionKeyEstablishmentError(
            "[-] Received RND.IC DOES NOT match with the earlier RND.IC")
    if resp_data[8:16] != rnd_ifd:
        raise SessionKeyEstablishmentError(
            "[-] Received RND.IFD DOES NOT match with the generated RND.IFD")

    k_ic = resp_data[16:]

    # Calculate XOR of KIFD and KIC
    ses_key_seed = strxor(k_ifd, k_ic)
    # Calculate session keys (ks_enc and ks_mac)
    print("[+] Computing session keys...")
    ks_enc = compute_key(ses_key_seed, "enc", "3DES")
    ks_mac = compute_key(ses_key_seed, "mac", "3DES")

    # Calculate send sequence counter
    ssc = rnd_ic[-4:] + rnd_ifd[-4:]

    sm_object.enc_alg = "3DES"
    sm_object.mac_alg = "DES"
    sm_object.pad_len = 8
    sm_object.ks_enc = ks_enc
    sm_object.ks_mac = ks_mac
    sm_object.ssc = ssc
Esempio n. 3
0
def program_logic(window: sg.Window):
    camera_id = -1
    mrz, _ = capture_mrz(window, camera_id)
    mrz_print = "\n".join(mrz)
    print(f"[i] MRZ Read:\n{mrz_print}")
    document_number, birthdate, expiry_date, issuing_country, name, surname = parse_mrz_text(
        mrz)
    mrz_information = other_mrz(document_number, birthdate, expiry_date)

    sm_object = SMObject(wait_for_card())

    atr = sm_object.channel.getATR()
    print("[+] Card ATR: " + toHexString(atr))

    # Select MF
    try:
        send(sm_object, APDU(b"\x00", b"\xA4", b"\x00", b"\x0C"))
    except CardCommunicationError:
        pass
    except CardConnectionException as ex:
        print(ex)
        pass
    else:
        print("[+] MF selected.")

    # Read EF.CardAccess
    ef_cardaccess = None
    try:
        ef_cardaccess = read_data_from_ef(window, sm_object, b"\x01\x1C",
                                          "EF.CardAccess")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.CardAccess.")
        pass
    except CardCommunicationError:
        pass
    except CardConnectionException as ex:
        print(ex)
        pass
    else:
        # print(f"[i] EF.CardAccess Read: {toHexString(list(ef_cardaccess))}")
        security_infos_efca = parse_security_infos(ef_cardaccess)
        # pace(security_infos_efca, sm_object)

    # Read EF.DIR
    try:
        ef_dir = read_data_from_ef(window, sm_object, b"\x2F\x00", "EF.DIR")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.DIR.")
    except CardCommunicationError:
        pass
    except CardConnectionException as ex:
        print(ex)
        pass
    else:
        print(f"[i] EF.DIR Read: {toHexString(list(ef_cardaccess))}")

    # Select eMRTD Applet
    print("[+] Selecting LDS DF AID: A0000002471001...")
    aid = bytes.fromhex("A0000002471001")
    try:
        send(
            sm_object,
            APDU(b"\x00",
                 b"\xA4",
                 b"\x04",
                 b"\x0C",
                 Lc=nb(len(aid)),
                 cdata=aid))
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return

    ## SECURE MESSAGING ##
    try:
        establish_bac_session_keys(sm_object, mrz_information.encode("utf-8"))
    except SessionKeyEstablishmentError as ex:
        print(ex)
        print("[-] Error while establishing BAC session keys")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return

    # Read EF.COM
    try:
        efcom = read_data_from_ef(window, sm_object, b"\x01\x1E", "EF.COM")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.COM.")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    else:
        # print(f"[i] EF.COM Read: {toHexString(list(efcom))}")
        ef_com_dg_list = parse_efcom(efcom)
        print(f"[i] DGs specified in EF.COM: {list(ef_com_dg_list.values())}")

    # Read EF.DG14
    try:
        dg14 = read_data_from_ef(window, sm_object, b"\x01\x0E", "EF.DG14")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.DG14.")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    else:
        # print(f"[i] EF.DG14 Read: {toHexString(list(dg14))}")
        security_infos_dg14 = parse_security_infos(dg14)
        for si in security_infos_efca:
            assert si in security_infos_dg14
            # print(dump_asn1(si))

    window.write_event_value("-RESTART-", "")
    return
Esempio n. 4
0
def main(
    window: sg.Window,
    args: argparse.Namespace,
    db: TinyDB,
    q: Queue,
    q2: Queue,
    lock: threading.Lock,
    lock2: threading.Lock,
    first_run: bool,
) -> None:
    """main function"""

    # Get dir arguments else fallback to EE certs
    CSCA_certs_dir = args.certs or Path("certs/csca_certs")
    crls_dir = args.certs or Path("certs/crls")
    output_dir = args.output
    output_files = not args.output is None
    camera_id = -1
    outfile: Union[TextIO, BinaryIO]

    if (args.online and first_run) or (
        not os.path.isdir(CSCA_certs_dir) or not os.path.isdir(crls_dir)
    ):
        window.write_event_value(
            "-DOWNLOAD CSCA CERT AND CRL-",
            [True, "text_download_csca_crl", "Downloading CSCA certificates and CRLs...", "white"],
        )
        download_certs(CSCA_certs_dir, crls_dir)
        window.write_event_value(
            "-DOWNLOAD CSCA CERT AND CRL-",
            [True, "text_download_csca_crl_status", "OK", "green"],
        )

    if first_run:
        dsccrl_dir = Path(os.path.join(os.path.dirname(CSCA_certs_dir), Path("icao_pkd_dsccrl")))
        ml_dir = Path(os.path.join(os.path.dirname(CSCA_certs_dir), Path("icao_pkd_ml")))
        window.write_event_value(
            "-BUILD CERT STORE-",
            [True, "build_cert_store", "Building certificate store...", "white"],
        )
        build_store(CSCA_certs_dir, crls_dir, ml_dir, dsccrl_dir)
        window.write_event_value(
            "-BUILD CERT STORE-",
            [True, "build_cert_store_status", "OK", "green"],
        )

        # create face detector network
        if args.biometric:
            from emrtd_face_access.face_compare import opencv_dnn_detector

            opencv_dnn_detector()

    if args.mrz:
        window.write_event_value(
            "-SHOW DOCUMENT TO CAMERA-",
            [
                True,
                "text_instruction",
                "Please show the Machine Readable Zone (MRZ) of your document to the camera.",
                "white",
            ],
        )
        window.write_event_value(
            "-READ MRZ-",
            [True, "read_mrz", "Trying to capture MRZ information...", "white"],
        )
        mrz, mrz_image = capture_mrz(window, camera_id)

        document_number, birthdate, expiry_date, issuing_country, name, surname = parse_mrz_text(
            mrz
        )
        mrz_information = other_mrz(document_number, birthdate, expiry_date)
        window.write_event_value(
            "-WRITE NAME-",
            [True, "text_name_surname", f"NAME: {name} {surname}", "white"],
        )
        window.write_event_value(
            "-WRITE DOC NUM-",
            [True, "text_doc_num", f"DOCUMENT NUMBER: {document_number}", "white"],
        )
        window.write_event_value(
            "-READ MRZ-",
            [True, "read_mrz_status", "OK", "green"],
        )

    print("[?] Please place your document onto the card reader.")
    window.write_event_value(
        "-PLACE DOCUMENT-",
        [
            True,
            "text_instruction",
            "Please place your document onto the card reader.",
            "white",
        ],
    )
    window.write_event_value(
        "-WAIT FOR DOCUMENT-",
        [True, "text_card_insert", "Waiting for a document...", "white"],
    )
    sm_object = SMObject(wait_for_card())
    window.write_event_value("-PLACE DOCUMENT-", [True, "text_instruction", "", "white"])
    window.write_event_value(
        "-WAIT FOR DOCUMENT-",
        [True, "text_card_insert_status", "OK", "green"],
    )
    atr = sm_object.channel.getATR()

    print("[+] Card ATR: " + toHexString(atr))

    ## DERIVATION OF DOCUMENT BASIC ACCESS KEYS (KENC AND KMAC) ##
    if args.ee:
        try:
            (
                mrz_information,
                document_number,
                personal_id_code,
                name,
                surname,
            ) = estonia_read_mrz(sm_object)
        except CardCommunicationError:
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardConnectionException as ex:
            print(ex)
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        else:
            issuing_country = "EST"
            window.write_event_value(
                "-WRITE NAME-",
                [True, "text_name_surname", f"NAME: {name} {surname}", "white"],
            )
            window.write_event_value(
                "-WRITE DOC NUM-",
                [True, "text_doc_num", f"DOCUMENT NUMBER: {document_number}", "white"],
            )
            window.write_event_value(
                "-WRITE ID CODE-",
                [True, "text_personal_code", f"PERSONAL ID CODE: {personal_id_code}", "white"],
            )
    if output_files:
        folder_name = create_output_folder(output_dir, document_number)

    if args.mrz and output_files:
        with open(os.path.join(folder_name, "mrz_text.txt"), "wt") as outfile:
            outfile.write("\n".join(mrz))

        mrz_image.save(os.path.join(folder_name, "mrz_photo.jpeg"))

    # Select eMRTD application
    print("[+] Selecting eMRTD Application ‘International AID’: A0000002471001...")
    aid = bytes.fromhex("A0000002471001")
    try:
        send(sm_object, APDU(b"\x00", b"\xA4", b"\x04", b"\x0C", Lc=nb(len(aid)), cdata=aid))
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return

    ## SECURE MESSAGING ##
    try:
        establish_bac_session_keys(sm_object, mrz_information.encode("utf-8"))
    except SessionKeyEstablishmentError as ex:
        print(ex)
        print("[-] Error while establishing BAC session keys")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return

    # Read EF.COM
    try:
        efcom = read_data_from_ef(window, sm_object, b"\x01\x1E", "EF.COM")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.COM.")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    else:
        if output_files:
            with open(os.path.join(folder_name, "EF_COM.BIN"), "wb") as outfile:
                outfile.write(efcom)
        ef_com_dg_list = parse_efcom(efcom)

    # Read EF.SOD
    try:
        efsod = read_data_from_ef(window, sm_object, b"\x01\x1D", "EF.SOD")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.SOD.")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    else:
        if output_files:
            with open(os.path.join(folder_name, "EF_SOD.BIN"), "wb") as outfile:
                outfile.write(efsod)

    window.write_event_value(
        "-PASSIVE AUTHENTICATION-",
        [True, "text_authentic", "Passive Authentication...", "white"],
    )
    pa_error = False
    ee_deviant_doc = False
    if issuing_country == "EST":
        try:
            with open(Path("certs/erpdeviationlist.bin"), "rb") as infile:
                deviation_docs = infile.read()
        except FileNotFoundError:
            pass
        else:
            if deviation_docs.find(document_number.encode("utf-8")) != -1:
                ee_deviant_doc = True
    try:
        passive_auth_return = passive_auth(efsod, ee_deviant_doc=ee_deviant_doc, dump=False)
    except PassiveAuthenticationCriticalError as ex:
        print(ex)
        window.write_event_value(
            "-PASSIVE AUTHENTICATION-",
            [False, "text_authentic_status", "ERROR", "red"],
        )
    else:
        if output_files:
            with open(os.path.join(folder_name, "CDS.der"), "wb") as outfile:
                outfile.write(passive_auth_return[2])
        if passive_auth_return[3] is None:
            pa_error = False
            hash_alg, data_group_hash_values, _, _ = passive_auth_return
        else:
            pa_error = True
            hash_alg, data_group_hash_values, _, exception = passive_auth_return
            print(exception)
            window.write_event_value(
                "-PASSIVE AUTHENTICATION-",
                [False, "text_authentic_status", "ERROR", "red"],
            )

    if atr in atr_exceptions and hash_alg == "sha256":
        hash_alg = "sha1"

    ef_sod_dg_list = get_dg_numbers(data_group_hash_values)

    if ef_com_dg_list != ef_sod_dg_list:
        print(
            "[-] EF.COM might have been changed, there are "
            "differences between EF_COM DGs and EF_SOD DGs!"
        )
        window.write_event_value(
            "-PASSIVE AUTHENTICATION-",
            [False, "text_authentic_status", "ERROR", "red"],
        )
        pa_error = True

    window.write_event_value(
        "-FILE VERIFICATION-",
        [True, "text_read_file", "Reading and verifying document files...", "white"],
    )

    file_read_error = False
    security_infos = []
    if b"\x0e" in ef_sod_dg_list:
        window.write_event_value(
            "-FILE VERIFICATION-",
            [True, "text_read_file_status", "EF.DG14", "yellow"],
        )
        try:
            DG = read_data_from_ef(window, sm_object, b"\x01" + b"\x0e", "EF.DG14")
        except EFReadError as ex:
            print(ex)
            print("[-] Error while reading file EF.DG14.")
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardCommunicationError:
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardConnectionException as ex:
            print(ex)
            window.write_event_value("-RAISED EXCEPTION-", "")
            return

        if not assert_dg_hash(DG, data_group_hash_values, hash_alg, b"\x0e"):
            pa_error = True
            window.write_event_value(
                "-PASSIVE AUTHENTICATION-",
                [False, "text_authentic_status", "ERROR", "red"],
            )
            window.write_event_value(
                "-FILE VERIFICATION-",
                [False, "text_read_file_status", "EF.DG14", "red"],
            )
            file_read_error = True
        else:
            window.write_event_value(
                "-FILE VERIFICATION-",
                [True, "text_read_file_status", "EF.DG14", "green"],
            )
        security_infos = parse_security_infos(DG)
        window.write_event_value(
            "-CHIP AUTHENTICATION-",
            [True, "text_copied_2", "Chip Authentication...", "white"],
        )
        try:
            chip_auth(security_infos, sm_object)
        except ChipAuthenticationError as ex:
            print(ex)
            window.write_event_value(
                "-CHIP AUTHENTICATION-",
                [False, "text_copied_2_status", "ERROR", "red"],
            )
        except CardCommunicationError:
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardConnectionException as ex:
            print(ex)
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        else:
            window.write_event_value(
                "-CHIP AUTHENTICATION-",
                [True, "text_copied_2_status", "OK", "green"],
            )

    if b"\x0f" in ef_sod_dg_list:
        window.write_event_value(
            "-FILE VERIFICATION-",
            [True, "text_read_file_status", "EF.DG15", "yellow"],
        )
        try:
            DG = read_data_from_ef(window, sm_object, b"\x01" + b"\x0f", "EF.DG15")
        except EFReadError as ex:
            print(ex)
            print("[-] Error while reading file EF.DG15.")
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardCommunicationError:
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardConnectionException as ex:
            print(ex)
            window.write_event_value("-RAISED EXCEPTION-", "")
            return

        if output_files:
            with open(os.path.join(folder_name, "EF.DG15.BIN"), "wb") as outfile:
                outfile.write(DG)
        if not assert_dg_hash(DG, data_group_hash_values, hash_alg, b"\x0f"):
            pa_error = True
            window.write_event_value(
                "-PASSIVE AUTHENTICATION-",
                [False, "text_authentic_status", "ERROR", "red"],
            )
            window.write_event_value(
                "-FILE VERIFICATION-",
                [False, "text_read_file_status", "EF.DG15", "red"],
            )
            file_read_error = True
        else:
            window.write_event_value(
                "-FILE VERIFICATION-",
                [True, "text_read_file_status", "EF.DG15", "green"],
            )
        window.write_event_value(
            "-ACTIVE AUTHENTICATION-",
            [True, "text_copied_1", "Active Authentication...", "white"],
        )
        try:
            active_auth(DG, sm_object, security_infos)
        except ActiveAuthenticationError as ex:
            print(ex)
            window.write_event_value(
                "-ACTIVE AUTHENTICATION-",
                [False, "text_copied_1_status", "ERROR", "red"],
            )
        except CardCommunicationError:
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardConnectionException as ex:
            print(ex)
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        else:
            window.write_event_value(
                "-ACTIVE AUTHENTICATION-",
                [True, "text_copied_1_status", "OK", "green"],
            )
    for dg, dgname in ef_sod_dg_list.items():
        if dg == b"\x0f" or dg == b"\x0e":
            # Active Authentication and Chip Authentication assumed completed
            continue

        if dg == b"\x03" or dg == b"\x04":
            # Sensitive Data: Finger and iris image data stored in the LDS
            # Data Groups 3 and 4, respectively. These data are considered
            # to be more privacy sensitive than data stored in the other
            # Data Groups.
            continue

        window.write_event_value(
            "-FILE VERIFICATION-",
            [True, "text_read_file_status", dgname, "yellow"],
        )
        try:
            DG = read_data_from_ef(window, sm_object, b"\x01" + dg, dgname)
        except EFReadError as ex:
            print(ex)
            print(f"[-] Error while reading file {dgname}.")
            if dg in [b"\x01", b"\x02"]:
                window.write_event_value("-RAISED EXCEPTION-", "")
                return
            continue
        except CardCommunicationError:
            window.write_event_value("-RAISED EXCEPTION-", "")
            return
        except CardConnectionException as ex:
            print(ex)
            window.write_event_value("-RAISED EXCEPTION-", "")
            return

        if output_files:
            with open(os.path.join(folder_name, dgname + ".BIN"), "wb") as outfile:
                outfile.write(DG)

        dg1_okay = True
        if not assert_dg_hash(DG, data_group_hash_values, hash_alg, dg):
            if dg == b"\x01":
                dg1_okay = False
            pa_error = True
            window.write_event_value(
                "-PASSIVE AUTHENTICATION-",
                [False, "text_authentic_status", "ERROR", "red"],
            )
            window.write_event_value(
                "-FILE VERIFICATION-",
                [False, "text_read_file_status", dgname, "red"],
            )
            file_read_error = True
        else:
            window.write_event_value(
                "-FILE VERIFICATION-",
                [True, "text_read_file_status", dgname, "green"],
            )

        if dg == b"\x02":
            id_image = get_jpeg_im(DG)
            window.write_event_value("-SHOW ID IMAGE-", [jpeg_to_png(id_image)])

        if dg == b"\x01":
            window.write_event_value(
                "-DOCUMENT EXPIRY CHECK-",
                [True, "document_expired", "Checking expiration status...", "white"],
            )
            mrz_read = get_dg1_content(DG)
            if dg1_okay:
                mrz_expiration_date = b""
                if len(mrz_read) == 90:
                    mrz_expiration_date = mrz_read[38:44]
                elif len(mrz_read) == 72:
                    mrz_expiration_date = mrz_read[57:63]
                elif len(mrz_read) == 88:
                    mrz_expiration_date = mrz_read[65:71]
                else:
                    print("[-] Error in MRZ that was read from DG1")
                    window.write_event_value(
                        "-DOCUMENT EXPIRY CHECK-",
                        [False, "document_expired_status", "ERROR", "red"],
                    )
                if mrz_expiration_date != b"":
                    valid = check_expiration(mrz_expiration_date)
                    if valid:
                        window.write_event_value(
                            "-DOCUMENT EXPIRY CHECK-",
                            [True, "document_expired_status", "OK", "green"],
                        )
                    else:
                        window.write_event_value(
                            "-DOCUMENT EXPIRY CHECK-",
                            [False, "document_expired_status", "EXPIRED", "red"],
                        )
            else:
                # Assume the document expired
                window.write_event_value(
                    "-DOCUMENT EXPIRY CHECK-",
                    [False, "document_expired_status", "ERROR", "red"],
                )

            if args.mrz:
                window.write_event_value(
                    "-MRZ COMPARE-",
                    [
                        True,
                        "text_mrz_compare",
                        "Comparing Machine Readable Zone with the DG1 inside the card...",
                        "white",
                    ],
                )
                mrz_scanned = str.encode("".join(mrz))
                if mrz_read != mrz_scanned:
                    print(
                        "[-] MRZ in DG1 doesn't match the MRZ read from the card!"
                        f"\nMRZ SCANNED:\n{mrz_scanned!s}\n\nMRZ READ:\n{mrz_read!s}"
                    )
                    window.write_event_value(
                        "-MRZ COMPARE-",
                        [
                            False,
                            "text_mrz_compare_status",
                            "ERROR",
                            "red",
                        ],
                    )
                else:
                    window.write_event_value(
                        "-MRZ COMPARE-",
                        [
                            True,
                            "text_mrz_compare_status",
                            "OK",
                            "green",
                        ],
                    )

            if db is not None:
                # Search MRZ in the db
                window.write_event_value(
                    "-CHECK DATABASE-",
                    [True, "check_database", "Checking database...", "white"],
                )
                database_obj = Query()
                if db.search(database_obj.mrz == "".join(mrz)) == []:
                    window.write_event_value(
                        "-CHECK DATABASE-",
                        [False, "check_database_status", "NOT FOUND", "red"],
                    )
                else:
                    window.write_event_value(
                        "-CHECK DATABASE-",
                        [True, "check_database_status", "OK", "green"],
                    )
            issuing_country = mrz_read[2:5]
            if issuing_country == b"EST":
                check_validity(window, document_number)

    if file_read_error:
        window.write_event_value(
            "-FILE VERIFICATION-",
            [False, "text_read_file_status", "ERROR", "red"],
        )
    else:
        window.write_event_value(
            "-FILE VERIFICATION-",
            [True, "text_read_file_status", "ALL OK", "green"],
        )

    if pa_error:
        window.write_event_value(
            "-PASSIVE AUTHENTICATION-",
            [False, "text_authentic_status", "ERROR", "red"],
        )
    else:
        window.write_event_value(
            "-PASSIVE AUTHENTICATION-",
            [True, "text_authentic_status", "OK", "green"],
        )

    if args.biometric:
        from emrtd_face_access.camera import capture_image
        from emrtd_face_access.face_compare import compare_faces
        from emrtd_face_access.image_operations import show_result

        print("[?] Please take a picture.")
        camera_image, face_location = capture_image(window, q, q2, lock2, camera_id)
        with lock:
            window.write_event_value(
                "-COMPARE RESULT-",
                [True, "text_face_compare", "Performing face comparison...", "white"],
            )
            comparison_result = compare_faces(
                id_image, camera_image, face_location, None if not output_files else folder_name
            )

            show_result(window, comparison_result)

            # termios.tcflush(sys.stdin, termios.TCIOFLUSH)
            # input("[?] Please take your ID card out and press [Enter] to run again.")
    window.write_event_value(
        "-TAKE ID OUT-",
        [
            True,
            "text_instruction",
            "Please take your document out and press [Enter] to run again.",
            "white",
        ],
    )
    window.write_event_value("-RUN COMPLETE-", "")
    return
Esempio n. 5
0
def estonia_read_mrz(sm_object: SMObject) -> Tuple[str, str, str, str, str]:
    """Read Estonian ID card information from personal data"""
    # reading personal data file (EstEID spec page 30)
    print(
        "[+] Selecting IAS ECC applet AID: A000000077010800070000FE00000100..."
    )
    ias_ecc_aid = bytes.fromhex("A000000077010800070000FE00000100")

    # exception caught in main program loop
    send(
        sm_object,
        APDU(b"\x00",
             b"\xA4",
             b"\x04",
             b"\x00",
             Lc=nb(len(ias_ecc_aid)),
             cdata=ias_ecc_aid),
    )
    print("[+] Selecting DF ID: 5000...")
    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x00"))
    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x07"))
    print("[+] Reading personal data files...")
    document_number = send(
        sm_object, APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                        Le=b"\x00")).decode("utf8")

    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x05"))
    date_of_birth = send(sm_object,
                         APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                              Le=b"\x00"))[:10].decode("utf8")
    date_of_birth = date_of_birth[-2:] + date_of_birth[3:5] + date_of_birth[:2]
    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x08"))
    date_of_expiry = send(sm_object,
                          APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                               Le=b"\x00")).decode("utf8")
    date_of_expiry = date_of_expiry[-2:] + date_of_expiry[
        3:5] + date_of_expiry[:2]
    # Construct the 'MRZ information'
    print("[+] Constructing the MRZ information...")
    mrz_information = (document_number +
                       calculate_check_digit(document_number) + date_of_birth +
                       calculate_check_digit(date_of_birth) + date_of_expiry +
                       calculate_check_digit(date_of_expiry))

    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x01"))
    surname = send(sm_object,
                   APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                        Le=b"\x00")).decode("utf8")
    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x02"))
    name = send(sm_object, APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                                Le=b"\x00")).decode("utf8")
    send(
        sm_object,
        APDU(b"\x00", b"\xA4", b"\x01", b"\x0C", Lc=b"\x02",
             cdata=b"\x50\x06"))
    personal_id_code = send(
        sm_object, APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                        Le=b"\x00")).decode("utf8")

    # Select LDS applet
    # A00000024710FF is applet id
    print("[+] Selecting LDS AID: A00000024710FF...")
    aid = bytes.fromhex("A00000024710FF")
    send(sm_object,
         APDU(b"\x00", b"\xA4", b"\x04", b"\x00", Lc=nb(len(aid)), cdata=aid))

    return mrz_information, document_number, personal_id_code, name, surname
def read_data_from_ef(window: sg.Window, sm_object: SMObject, fid: bytes,
                      fname: str) -> bytes:
    """
    Read the data from file id fid and return

    sm_object -- Necessary secure messaging object (Encryption session key etc.)
    fid -- File id
    fname -- Printed file name
    :returns: data from the file
    """
    # Select File
    print("[+] Selecting file: " + fname)

    # exception caught in main program loop
    send(sm_object,
         APDU(b"\x00", b"\xA4", b"\x02", b"\x0C", Lc=b"\x02", cdata=fid))

    # Read Binary of first four bytes
    print("[+] Read first 4 bytes of selected file...")

    # exception caught in main program loop
    data = send(sm_object, APDU(b"\x00", b"\xB0", b"\x00", b"\x00",
                                Le=b"\x04"))

    if data == b"":
        raise EFReadError("[-] No reply from card")
    elif len(data) != 4:
        raise EFReadError("[-] Broken reply from card")

    data_len = len2int(data)

    offset = 4

    # Read the rest of the bytes
    print("[+] Read the rest of the bytes of selected file...")
    # IAS_ECC_v1 page 121 "Particular issue for the READ BINARY command"
    while offset < data_len:
        if (
                data_len - offset < 0xFA
        ):  # 0xFA because all the cards I have access to only send 250 bytes in BAC SM 242 in AES SM
            le = bytes([data_len - offset])
        else:
            le = b"\x00"
        window.write_event_value(
            "-PROGRESS BAR-",
            [offset, data_len],
        )

        # exception caught in main program loop
        decrypted_data = send(
            sm_object,
            APDU(b"\x00",
                 b"\xB0",
                 bytes([offset >> 8]),
                 bytes([offset & 0xFF]),
                 Le=le),
        )

        if decrypted_data == b"":
            raise EFReadError("[-] No reply from card")

        data += decrypted_data
        offset += len(decrypted_data)

    window.write_event_value(
        "-PROGRESS BAR-",
        [offset, data_len],
    )

    if offset != data_len:
        raise EFReadError("[-] Error while processing a file.")
    window.write_event_value(
        "-PROGRESS BAR-",
        [0, 100],
    )

    return data
def secure_messaging(sm_object: SMObject, apdu: APDU) -> bytes:
    """
    Sends an APDU using secure messaging.
    """
    if sm_object.enc_alg is None:
        return apdu.get_command_header() + (apdu.Lc or b"") + (
            apdu.cdata or b"") + (apdu.Le or b"")
        raise ValueError("[-] Encryption algorithm is not set")
    if sm_object.mac_alg is None:
        raise ValueError("[-] Mac algorithm is not set")
    if sm_object.pad_len == 0:
        raise ValueError("[-] Padding length is 0")
    if sm_object.ks_enc is None or sm_object.ks_mac is None:
        raise ValueError("[-] Session keys are not set")
    if sm_object.ssc is None:
        raise ValueError("[-] SSC is not set")

    apdu.cla = bytes([apdu.cla[0] | 0x0C])

    sm_object.increment_ssc()

    payload = b""
    if apdu.cdata is not None:
        data = padding_method_2(apdu.cdata, sm_object.pad_len)
        if sm_object.enc_alg == "3DES":
            des_cipher = DES3.new(sm_object.ks_enc,
                                  DES3.MODE_CBC,
                                  iv=bytes([0] * 8))
            encrypted_data = des_cipher.encrypt(data)
        elif sm_object.enc_alg == "AES":
            ssc_enc = AES.new(sm_object.ks_enc,
                              AES.MODE_ECB).encrypt(sm_object.ssc)
            aes_cipher = AES.new(sm_object.ks_enc, AES.MODE_CBC, iv=ssc_enc)
            encrypted_data = aes_cipher.encrypt(data)

        if int.from_bytes(apdu.ins, byteorder="big") % 2 == 0:
            # For a command with even INS, any command data is encrypted
            # and capsulated in a Tag 87 with padding indicator (01).
            do87 = b"\x87" + asn1_len(
                b"\x01" + encrypted_data) + b"\x01" + encrypted_data
            payload += do87
        else:
            # For a command with odd INS, any command data is encrypted
            # and capsulated in a Tag 85 without padding indicator.
            do85 = b"\x85" + asn1_len(encrypted_data) + encrypted_data
            payload += do85

    if apdu.Le is not None:
        # Commands with response (Le field not empty)
        # have a protected Le-field (Tag 97) in the command data.
        do97 = b"\x97" + asn1_len(apdu.Le) + apdu.Le
        payload += do97

    padded_header = padding_method_2(apdu.get_command_header(),
                                     sm_object.pad_len)
    n = padding_method_2(sm_object.ssc + padded_header + payload,
                         sm_object.pad_len)
    cc = compute_mac(sm_object.ks_mac, n, sm_object.mac_alg)

    do8e = b"\x8E" + asn1_len(cc) + cc

    payload += do8e
    protected_apdu = apdu.get_command_header() + bytes([len(payload)
                                                        ]) + payload + b"\x00"

    return protected_apdu
def active_auth(dg15: bytes, sm_object: SMObject, security_infos: List[bytes]):
    """
    Do active authentication with DG15
    """
    # Generate 8 random bytes
    rnd_ifd = urandom(8)

    # exception caught in main program loop
    data = send(
        sm_object,
        APDU(b"\x00",
             b"\x88",
             b"\x00",
             b"\x00",
             Lc=b"\x08",
             cdata=rnd_ifd,
             Le=b"\x00"))

    if data == b"":
        raise ActiveAuthenticationError("[-] No reply from card.")

    i = asn1_node_root(dg15)
    i = asn1_node_first_child(dg15, i)
    pub_key = asn1_get_all(dg15, i)

    i = asn1_node_first_child(dg15, i)
    i = asn1_node_first_child(dg15, i)

    if asn1_get_all(dg15, i) == encode_oid_string("1.2.840.10045.2.1"):  # ECC
        r = data[:len(data) // 2]
        s = data[len(data) // 2:]
        signature = asn1_sequence(asn1_integer(r) + asn1_integer(s))
        ec_pub = EC.pub_key_from_der(pub_key)
        if ec_pub.check_key() != 1:
            raise ActiveAuthenticationError(
                "[-] Active Authentication (AA) failed! Problem in EC Public Key!"
            )

        try:
            hash_type = find_hash_name(security_infos)
        except ValueError as ex:
            raise ActiveAuthenticationError(
                "[-] Active Authentication (AA) failed! Problem in Security Infos hash type!"
            ) from ex
        # for hash_type in ["sha224", "sha256", "sha384", "sha512"]:
        try:
            result = ec_pub.verify_dsa_asn1(
                hashlib.new(hash_type, rnd_ifd).digest(), signature)
        except EC.ECError as ex:
            print("[-] Error in EC function " + ex)
            raise ActiveAuthenticationError(
                "[-] Error in verify_dsa_asn1 of M2Crypto.EC") from ex
        if result == 1:
            print("[+] Active Authentication (AA) completed successfully!")
        else:
            raise ActiveAuthenticationError(
                "[-] Active Authentication (AA) failed!")

    elif asn1_get_all(dg15,
                      i) == encode_oid_string("1.2.840.113549.1.1.1"):  # RSA
        j = asn1_node_root(pub_key)
        j = asn1_node_first_child(pub_key, j)
        j = asn1_node_next(pub_key, j)

        rsa_pub_key = asn1_get_value_of_type(pub_key, j, "BIT STRING")
        if rsa_pub_key[0] != 0x00:
            raise ActiveAuthenticationError(
                "[-] An issue with the RSA key! Padding 0x00 is expected")

        rsa_pub_key = rsa_pub_key[1:]
        j = asn1_node_root(rsa_pub_key)
        j = asn1_node_first_child(rsa_pub_key, j)
        n_der = asn1_get_value_of_type(rsa_pub_key, j, "INTEGER")
        j = asn1_node_next(rsa_pub_key, j)
        e_der = asn1_get_value_of_type(rsa_pub_key, j, "INTEGER")
        n = int.from_bytes(n_der, byteorder="big")
        e = int.from_bytes(e_der, byteorder="big")

        # rsa_key = RSA.import_key(pub_key)
        # https://stackoverflow.com/a/60132608/6077951

        msg = int.from_bytes(data, byteorder="big")
        dec = pow(msg, e, n).to_bytes(len(data), byteorder="big")

        if dec[-1] == 0xCC:
            if dec[-2] == 0x38:
                hash_alg = "sha224"
            elif dec[-2] == 0x34:
                hash_alg = "sha256"
            elif dec[-2] == 0x36:
                hash_alg = "sha384"
            elif dec[-2] == 0x35:
                hash_alg = "sha512"
            t = 2
        elif dec[-1] == 0xBC:
            hash_alg = "sha1"
            t = 1
        else:
            raise ActiveAuthenticationError(
                "[-] Error while Active Authentication!")

        def compare_aa(hash_object):
            # k = rsa_key.size_in_bits()
            # Lh = hash_object.digest_size * 8
            # Lm1 = (k - Lh - (8 * t) - 4 - 4) // 8
            D = dec[-hash_object.digest_size - t:-t]
            M1 = dec[1:-hash_object.digest_size - t]
            Mstar = M1 + rnd_ifd
            hash_object.update(Mstar)
            Dstar = hash_object.digest()
            return hmac.compare_digest(D, Dstar)

        hash_object = hashlib.new(hash_alg)
        if compare_aa(hash_object):
            print("[+] Active Authentication (AA) completed successfully!")
        else:
            raise ActiveAuthenticationError(
                "[-] Active Authentication (AA) failed!")
Esempio n. 9
0
def database_builder_loop(window: sg.Window):
    camera_id = -1
    mrz, _ = capture_mrz(window, camera_id)
    mrz_scan = "".join(mrz)
    print(f"[i] MRZ Read:\n{mrz_scan}")
    document_number, birthdate, expiry_date, _, _, _ = parse_mrz_text(mrz)
    mrz_information = other_mrz(document_number, birthdate, expiry_date)

    sm_object = SMObject(wait_for_card())

    atr = sm_object.channel.getATR()
    print("[+] Card ATR: " + toHexString(atr))

    # Select eMRTD Applet
    print("[+] Selecting LDS DF AID: A0000002471001...")
    aid = bytes.fromhex("A0000002471001")
    try:
        send(sm_object, APDU(b"\x00", b"\xA4", b"\x04", b"\x0C", Lc=nb(len(aid)), cdata=aid))
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return

    ## SECURE MESSAGING ##
    try:
        establish_bac_session_keys(sm_object, mrz_information.encode("utf-8"))
    except SessionKeyEstablishmentError as ex:
        print(ex)
        print("[-] Error while establishing BAC session keys")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return

    # Read EF.DG1
    try:
        dg1 = read_data_from_ef(window, sm_object, b"\x01\x01", "EF.DG1")
    except EFReadError as ex:
        print(ex)
        print("[-] Error while reading file EF.DG1.")
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardCommunicationError:
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    except CardConnectionException as ex:
        print(ex)
        window.write_event_value("-RAISED EXCEPTION-", "")
        return
    else:
        mrz_read = get_dg1_content(dg1).decode("utf-8")
        print(mrz_read)
        if mrz_read == mrz_scan:
            window.write_event_value("-SHOW WARNING-", mrz_read)
        else:
            window.write_event_value("-PROBLEM IN EITHER READ OR DOCUMENT-", "")