Beispiel #1
0
def derive_visa_sm_sk(icc_mk: bytes, atc: bytes) -> bytes:
    r"""Visa Secure Messaging Session Key Derivation

    Parameters
    ----------
    icc_mk : bytes
        Binary ICC Master Key to derive session key from.
        Has to be a valid DES key.
    atc : bytes
        Binary data from tag 9F36 (Application Transaction Counter).

    Returns
    -------
    sk : bytes
        Binary 16-byte Session Key.

    Raises
    ------
    ValueError
        ICC Master Key must be a double length DES key
        ATC value must be 2 bytes long

    Examples
    --------
    >>> from pyemv import kd
    >>> mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210")
    >>> atc = bytes.fromhex("001C")
    >>> sk = kd.derive_visa_sm_sk(mk, atc)
    >>> sk.hex().upper()
    '0123456789ABCDF2FEDCBA987654CDF2'
    """
    if len(icc_mk) != 16:
        raise ValueError("ICC Master Key must be a double length DES key")

    if len(atc) != 2:
        raise ValueError("ATC value must be 2 bytes long")

    # SK Key A (i.e. first 8 bytes) = r _xor MK Key A
    r = b"\x00" * 6 + atc
    sk_a = _xor(r, icc_mk[:8])

    # SK Key B (i.e. second 8 bytes) = r _xor MK Key B
    r = b"\x00" * 6 + _xor(atc, b"\xff\xff")
    sk_b = _xor(r, icc_mk[8:])

    return _adjust_key_parity(sk_a + sk_b)
Beispiel #2
0
def derive_icc_mk_a(iss_mk: bytes,
                    pan: bytes,
                    psn: Optional[bytes] = None) -> bytes:
    r"""ICC Master Key Derivation. EMV Option A.
    Uses PAN, PAN Sequence Number, MK ISS, Triple DES.

    Parameters
    ----------
    iss_mk : bytes
        Binary Issuer Master Key to derive ICC Master Key from.
        Has to be a valid DES key.
    pan : bytes
        ASCII Application Primary Account Number.
    psn : bytes, optional
        ASCII 2-digit PAN Sequence Number (default 00).

    Returns
    -------
    icc_mk : bytes
        Binary 16-byte ICC Master Key.

    Notes
    -----
    Derived from Issuer Master Key (iss_mk).
    Uses EMV Option A - Master Key Derivation method which uses
    the PAN and PAN sequence number, as defined in EMV Book 2, Annex A.

    When a card is personalised the issuer will take the 3 iss_mk keys
    and calculate the 3 icc_mk keys to be stored on the card.
        - icc_mk_ac - used for the transaction cryptograms (ARQC, TC or AAC)
        - icc_mk_smi - used for Issuer Script Integrity
        - icc_mk_smc - used for Issuer Script Confidentiality

    For further details see also:
        - EMV 4.3 Book 2 Annex A 1.4 Master Key Derivation
        - EMV 4.3 Book 2 Annex A 1.4.1 Option A

    Examples
    --------
    >>> from pyemv import kd
    >>> iss_mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210")
    >>> icc_mk = kd.derive_icc_mk_a(iss_mk, pan=b"12345678901234567", psn=b"01")
    >>> icc_mk.hex().upper()
    '73AD54688CEF2934B0979857E3C719F1'
    """
    if psn is None:
        psn = b"00"

    # Data A must be at most 16 digits, right-justified,
    # zero-padded from the left.
    data_a = _binascii.a2b_hex((pan + psn)[-16:].zfill(16))

    # Data B is inverted data A
    data_b = _xor(data_a, b"\xFF" * len(data_a))

    icc_mk = _encrypt_tdes_ecb(iss_mk, data_a + data_b)

    return _adjust_key_parity(icc_mk)
Beispiel #3
0
def generate_arpc_1(sk_ac: bytes, arqc: bytes, arpc_rc: bytes) -> bytes:
    r"""Generate Authorisation Response Cryptogram (ARPC) using method 1.
    Method for the generation of an 8-byte ARPC consists of applying
    the Triple-DES algorithm to:

        - 8-byte binary ARQC
        - 2-byte binary Authorisation Response Code (ARPC-RC)

    Parameters
    ----------
    sk_ac : bytes
        Binary ICC Session Key for AC. Has to be a valid DES key.
    arqc : bytes
        Binary 8-byte Authorisation Request Cryptogram (ARQC).
    arpc_rc : bytes
        Binary 2-byte ARPC response code.

    Returns
    -------
    arpc : bytes
        Returns binary 8-byte Authorisation Response Cryptogram (ARPC).
        The resulting issuer authentication data (tag 91) is:

            91 || Len || ARPC || ARPC-RC

    Raises
    ------
    ValueError
        Session Key must be a double length DES key
        ARQC must be 8 bytes long
        ARPC-RC must be 2 bytes long

    Notes
    -----
    After the host has validated the cryptogram sent by the terminal/reader
    in the authorisation request it will generate an Authorisation Response
    cryptogram (ARPC) which will then be returned in the response message
    along with the ARPC response code and ultimately validated by the card.

    For further details see also:
        - EMV 4.3 Book 2 Section 8.2 Issuer Authentication
        - EMV 4.3 Book 2 Section 8.2.1 ARPC Method 1

    Examples
    --------
    >>> from pyemv import ac
    >>> sk_ac = bytes.fromhex("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB")
    >>> arqc = bytes.fromhex("1234567890ABCDEF")
    >>> arpc_rc = bytes.fromhex("0000")
    >>> arpc = ac.generate_arpc_1(sk_ac, arqc, arpc_rc)
    >>> arpc.hex().upper()
    'F5E6F44147E2F1B0'
    """
    if len(sk_ac) != 16:
        raise ValueError("Session Key must be a double length DES key")

    if len(arqc) != 8:
        raise ValueError("ARQC must be 8 bytes long")

    if len(arpc_rc) != 2:
        raise ValueError("ARPC-RC must be 2 bytes long")

    return _encrypt_tdes_cbc(sk_ac, b"\x00\x00\x00\x00\x00\x00\x00\x00",
                             _xor(arpc_rc + (b"\00" * 6), arqc))
Beispiel #4
0
def derive_icc_mk_b(iss_mk: bytes,
                    pan: bytes,
                    psn: Optional[bytes] = None) -> bytes:
    r"""ICC Master Key Derivation. EMV Option B.
    Uses PAN, PAN Sequence Number, MK ISS, Triple DES, SHA-1 and
    decimalisation of hex digits.

    Parameters
    ----------
    iss_mk : bytes
        Binary Issuer Master Key to derive ICC Master Key from.
        Has to be a valid DES key.
    pan : bytes
        ASCII Application Primary Account Number.
    psn : bytes, optional
        ASCII 2-digit PAN Sequence Number (default 00).

    Returns
    -------
    icc_mk : bytes
        Binary 16-byte ICC Master Key

    Notes
    -----
    Derived from Issuer Master Key (iss_mk).
    Uses EMV Option B - Master Key Derivation method which uses
    the PAN and PAN sequence number, as defined in EMV Book 2, Annex A.

    When a card is personalised the issuer will take the 3 iss_mk keys
    and calculate the 3 icc_mk keys to be stored on the card.
        - icc_mk_ac - used for the transaction cryptograms (ARQC, TC or AAC)
        - icc_mk_smi - used for Issuer Script Integrity
        - icc_mk_smc - used for Issuer Script Confidentiality

    For further details see also:
        - EMV 4.3 Book 2 Annex A 1.4 Master Key Derivation
        - EMV 4.3 Book 2 Annex A 1.4.2 Option B

    Examples
    --------
    >>> from pyemv import kd
    >>> iss_mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210")
    >>> icc_mk = kd.derive_icc_mk_b(iss_mk, pan=b"12345678901234567", psn=b"01")
    >>> icc_mk.hex().upper()
    'AD406D7F6D7570916D75E5DCAB8CF737'
    """
    # For PANs with length of 16 or less method B works as method A
    if len(pan) <= 16:
        return derive_icc_mk_a(iss_mk, pan, psn)

    if psn is None:
        psn = b"00"

    # Data A must be an even number of digits,
    # right-justified, zero-padded from the left.
    if len(pan) % 2:
        pan_psn = _binascii.a2b_hex(b"0" + pan + psn)
    else:
        pan_psn = _binascii.a2b_hex(pan + psn)

    # Hash PAN || PAN sequence
    digest = _hashlib.sha1(pan_psn).hexdigest()

    # Get first 16 digits out the hash value.
    result = "".join(filter(str.isdigit, digest))[:16]

    # If there are not enough digits, substitute
    # letters using the following decimalization table:
    # Input a b c d e f
    # Table 0 1 2 3 4 5
    if len(result) < 16:
        digest = "".join(filter((lambda x: x in ("abcdef")), digest))
        digest = digest.translate({
            97: 48,
            98: 49,
            99: 50,
            100: 51,
            101: 52,
            102: 53
        })
        result = result + digest[:16 - len(result)]

    data_a = _binascii.a2b_hex(result)

    # Data B is inverted data A
    data_b = _xor(data_a, b"\xFF" * len(data_a))

    icc_mk = _encrypt_tdes_ecb(iss_mk, data_a + data_b)

    return _adjust_key_parity(icc_mk)
Beispiel #5
0
def format_vis_pin_block(
    icc_mk_ac: bytes, pin: bytes, current_pin: Optional[bytes] = None
) -> bytes:
    r"""Format VIS PIN block with or without the current PIN.

    Parameters
    ----------
    icc_mk_ac : bytes
        Binary 16-byte ICC Master Key for Application Cryptogram
        Has to be a valid DES key.
    pin : bytes
        New ASCII Personal Identification Number.
    current_pin : bytes, optional
        Current ASCII Personal Identification Number (optional). If present
        VIS PIN block is generated using current PIN.

    Returns
    -------
    pin_block : bytes
        Binary 16-byte VIS PIN block

    Raises
    ------
    ValueError
        PIN must be between 4 and 12 digits long
        Current PIN must be between 4 and 12 digits long
        ICC Master Key for AC must be a double length DES key

    Examples
    --------
    >>> from pyemv import sm
    >>> icc_mk_ac = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210")
    >>> sm.format_vis_pin_block(icc_mk_ac, b"1234").hex().upper()
    '041234FF76543210'
    """
    if len(pin) < 4 or len(pin) > 12:
        raise ValueError("PIN must be between 4 and 12 digits long")

    if len(icc_mk_ac) != 16:
        raise ValueError("ICC Master Key for AC must be a double length DES key")

    # 4 right-most bytes of ICC MK AC Key A padded with 0x00 to form an 8-byte block
    block_a = b"\x00" * 4 + icc_mk_ac[4:8]

    # PIN length as 1 byte concatenated with PIN then F-padded to form an 8 byte block
    block_b = len(pin).to_bytes(1, _sys.byteorder) + _binascii.a2b_hex(
        pin + b"F" * (14 - len(pin))
    )

    pin_block = _xor(block_a, block_b)

    # Generate VIS PIN block using current PIN
    if current_pin is not None:
        if len(current_pin) < 4 or len(current_pin) > 12:
            raise ValueError("Current PIN must be between 4 and 12 digits long")

        pin_block = _xor(
            pin_block, _binascii.a2b_hex(current_pin + b"0" * (16 - len(current_pin)))
        )

    return pin_block