Exemple #1
0
    def derive(x: bytes, y: bytes, j: int) -> bytes:
        """Map two 16-byte numbers X and Y and an integer j onto a 16-byte number."""
        j_mod_b = int.to_bytes(j % branch_factor, 8, "big")

        # (DES3(X)[YL XOR (j mod b)]
        l_data = _tools.xor(y[:8], j_mod_b)
        l_data = _tools.encrypt_tdes_ecb(x, l_data)

        # DES3(X)[YR XOR (j mod b) XOR 'F0']
        r_data = _tools.xor(y[8:], j_mod_b)
        r_data = _tools.xor(r_data, b"\x00" * 7 + b"\xF0")
        r_data = _tools.encrypt_tdes_ecb(x, r_data)
        return l_data + r_data
Exemple #2
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
    ValueError
        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 = _tools.xor(r, icc_mk[:8])

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

    return _tools.adjust_key_parity(sk_a + sk_b)
Exemple #3
0
def derive_icc_mk_b(iss_mk: bytes,
                    pan: Union[bytes, str],
                    psn: Optional[Union[bytes, str]] = 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 or str
        ASCII Application Primary Account Number.
    psn : bytes or str, 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="12345678901234567", psn="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 = "00"

    if isinstance(psn, bytes):
        psn = psn.decode("ascii")

    if isinstance(pan, bytes):
        pan = pan.decode("ascii")

    # 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("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 = _tools.xor(data_a, b"\xFF" * len(data_a))

    icc_mk = _tools.encrypt_tdes_ecb(iss_mk, data_a + data_b)

    return _tools.adjust_key_parity(icc_mk)
Exemple #4
0
def derive_icc_mk_a(iss_mk: bytes,
                    pan: Union[bytes, str],
                    psn: Optional[Union[bytes, str]] = 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 or str
        ASCII Application Primary Account Number.
    psn : bytes or str, 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="12345678901234567", psn="01")
    >>> icc_mk.hex().upper()
    '73AD54688CEF2934B0979857E3C719F1'
    """
    if psn is None:
        psn = "00"

    if isinstance(psn, bytes):
        psn = psn.decode("ascii")

    if isinstance(pan, bytes):
        pan = pan.decode("ascii")

    # 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 = _tools.xor(data_a, b"\xFF" * len(data_a))

    icc_mk = _tools.encrypt_tdes_ecb(iss_mk, data_a + data_b)

    return _tools.adjust_key_parity(icc_mk)
Exemple #5
0
def format_vis_pin_block(
    icc_mk_ac: bytes,
    pin: Union[bytes, str],
    current_pin: Optional[Union[bytes, str]] = 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 or str
        New ASCII Personal Identification Number.
    current_pin : bytes or str, 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, "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")

    if isinstance(pin, bytes):
        pin = pin.decode("ascii")

    if isinstance(current_pin, bytes):
        current_pin = current_pin.decode("ascii")

    # 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 + "F" * (14 - len(pin))
    )

    pin_block = _tools.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 = _tools.xor(
            pin_block, _binascii.a2b_hex(current_pin + "0" * (16 - len(current_pin)))
        )

    return pin_block
Exemple #6
0
def derive_emv2000_tree_sk(
    icc_mk: bytes,
    atc: bytes,
    height: int = 8,
    branch_factor: int = 4,
    iv: bytes = b"\x00" * 16,
) -> bytes:
    r"""EMV2000-Tree 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).
    height : int
        Height value used for EMV-Tree derivation. Height controls
        the number of levels of intermediate keys in the tree
        excluding the base level. Set to either 8 or 16.
        The specification recommends value 8. Defaults to 8.
    branch_factor : int
        Branch factor value used for EMV-Tree derivation. Branch factor
        controls number of "child" keys a "parent" key derives.
        The specification recommends value 4. Defaults to 4.
    iv : bytes
        16-byte binary initialization vector used for EMV-Tree derivation.
        The specification recommends IV value of zeros. Defaults to 0s.

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

    Raises
    ------
    ValueError
        ICC Master Key must be a double length DES key
    ValueError
        ATC value must be 2 bytes long
    ValueError
        Initialization vector value must be 16 bytes long
    ValueError
        Number of possible session keys must exceed maximum ATC value

    Notes
    -----
    For more information see:
        - EMV 4.1 Book 2 Annex A 1.3 Session Key Derivation
        - EMV 4.1 Book 2 Annex A 1.3.1 Description
        - EMV 4.1 Book 2 Annex A 1.3.2 Implementation

    This method was replaced by common session key derivation in 2005
    and should not be used for new development.
    See EMVCo specification update bulletin 46 (SU-46).

    Recommended branch factor and tree height combinations are as follow.
    Both combinations produce enough session keys for every possible ATC value.
        - Branch factor 2 and tree height 16
        - Branch factor 4 and tree height 8

    Examples
    --------
    >>> from pyemv import kd
    >>> mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210")
    >>> atc = bytes.fromhex("001C")
    >>> sk = kd.derive_emv2000_tree_sk(mk, atc, 8, 4)
    >>> sk.hex().upper()
    'E5BF6D1067F194B0A89B7F5D83BC64A2'
    """
    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")

    if len(iv) != 16:
        raise ValueError("Initialization vector value must be 16 bytes long")

    # The number of possible session keys (branch_factor ** height)
    # must exceed the maximum value of the ATC which is 2 ** 16 - 1.
    if branch_factor**height < 65535:
        raise ValueError(
            "Number of possible session keys must exceed maximum ATC value")

    # F(X,Y,j) := (DES3(X)[YL XOR (j mod b)] || DES3(X)[YR XOR (j mod b) XOR 'F0'])
    def derive(x: bytes, y: bytes, j: int) -> bytes:
        """Map two 16-byte numbers X and Y and an integer j onto a 16-byte number."""
        j_mod_b = int.to_bytes(j % branch_factor, 8, "big")

        # (DES3(X)[YL XOR (j mod b)]
        l_data = _tools.xor(y[:8], j_mod_b)
        l_data = _tools.encrypt_tdes_ecb(x, l_data)

        # DES3(X)[YR XOR (j mod b) XOR 'F0']
        r_data = _tools.xor(y[8:], j_mod_b)
        r_data = _tools.xor(r_data, b"\x00" * 7 + b"\xF0")
        r_data = _tools.encrypt_tdes_ecb(x, r_data)
        return l_data + r_data

    # GP = Grandparent Key
    # IK = Intermediate Key
    # P  = Parent Key
    # H  = Height of the tree
    def walk(j: int, h: int) -> _typing.Tuple[bytes, bytes]:
        """Returns P and GP"""
        # Base case: P = ICC MK, GP = IV
        if h == 0:
            return icc_mk, iv
        p, gp = walk(j // branch_factor, h - 1)
        # Derives an IK from P and GP
        # IK becomes the new parent and current P becomes the new GP
        return derive(p, gp, j), p

    atc_num = int.from_bytes(atc, "big")

    # Derive IKs from the bottom of the tree to the second to last level
    # because GP from that level is required for SK.
    p, gp = walk(atc_num // branch_factor, height - 1)

    # Derive SK from a new IK at the tree height XOR'd by GP.
    sk = _tools.xor(derive(p, gp, atc_num), gp)
    return _tools.adjust_key_parity(sk)