def key_check_digits(key: bytes, length: int = 2) -> bytes: r"""Calculate Triple DES key check digits. Parameters ---------- key : bytes Binary key to provide check digits for. Has to be a valid DES key. length : int, optional Number of key check digits bytes provided in the response (default 2). Returns ------- check_digits : bytes Binary check digits (`length` bytes) Examples -------- >>> from pyemv import tools >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> tools.key_check_digits(key).hex().upper() '08D7' """ cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) encryptor = cipher.encryptor() return encryptor.update(b"\x00\x00\x00\x00\x00\x00\x00\x00")[:length]
def encrypt_tdes_cbc(key: bytes, iv: bytes, data: bytes) -> bytes: r"""Encrypt data using Triple DES CBC algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. iv : bytes Binary initial initialization vector for CBC. data : bytes Binary data to be encrypted. Returns ------- encrypted_data : bytes Binary encrypted data. Examples -------- >>> from pyemv.tools import encrypt_tdes_cbc >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> iv = bytes.fromhex("0000000000000000") >>> encrypt_tdes_cbc(key, iv, b"12345678").hex().upper() '41D2FFBA3CDC15FE' """ cipher = _Cipher( _algorithms.TripleDES(key), _modes.CBC(iv), backend=_default_backend(), ) return cipher.encryptor().update(data)
def encrypt_tdes_ecb(key: bytes, data: bytes) -> bytes: r"""Encrypt data using Triple DES ECB algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. data : bytes Binary data to be encrypted. Returns ------- encrypted_data : bytes Binary encrypted data. Examples -------- >>> from pyemv.tools import encrypt_tdes_ecb >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> encrypt_tdes_ecb(key, b"12345678").hex().upper() '41D2FFBA3CDC15FE' """ cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) return cipher.encryptor().update(data)
def generate_kcv(key: bytes, length: int = 2) -> bytes: r"""Generate DES key checksum value (KCV). Parameters ---------- key : bytes Binary key to provide check digits for. Has to be a valid DES key. length : int, optional Number of KCV bytes returned (default 2). Returns ------- kcv : bytes Binary KCV (`length` bytes) Examples -------- >>> import psec >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> psec.des.generate_kcv(key).hex().upper() '08D7' """ cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) encryptor = cipher.encryptor() return encryptor.update(b"\x00\x00\x00\x00\x00\x00\x00\x00")[:length]
def _aes256cbc_encrypt(key, iv, plaintext): algo = _AES(key) mode = _CBC(iv) backend = _default_backend() cipher = _Cipher(algo, mode, backend) encryptor = cipher.encryptor() ciphertext = encryptor.update(plaintext) ciphertext += encryptor.finalize() return ciphertext
def encrypt(self, key, iv, data): if len(key) != self.key_size: raise EncrError('Key must be of the indicated size {}'.format( self.key_size)) _cipher = _Cipher(self._algorithm(key), modes.CBC(iv), backend=self._backend) encryptor = _cipher.encryptor() return encryptor.update(data) + encryptor.finalize()
def decrypt_tdes_cbc(key: bytes, iv: bytes, data: bytes) -> bytes: r"""Decrypt data using Triple DES CBC algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. iv : bytes Binary initial initialization vector for CBC. Has to be 8 bytes long. data : bytes Binary data to be decrypted. Has to be multiple of 8 bytes. Returns ------- decrypted_data : bytes Binary decrypted data. Raises ------ ValueError Data length must be multiple of DES block size 8. Examples -------- >>> import psec >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> iv = bytes.fromhex("0000000000000000") >>> psec.des.decrypt_tdes_cbc(key, iv, bytes.fromhex("41D2FFBA3CDC15FE")) b'12345678' """ if len(data) < 8 or len(data) % 8 != 0: raise ValueError( f"Data length ({str(len(data))}) must be multiple of DES block size 8." ) cipher = _Cipher( _algorithms.TripleDES(key), _modes.CBC(iv), backend=_default_backend(), ) return cipher.decryptor().update(data)
def encrypt_tdes_ecb(key: bytes, data: bytes) -> bytes: r"""Encrypt data using Triple DES ECB algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. data : bytes Binary data to be encrypted. Has to be multiple of 8 bytes. Returns ------- encrypted_data : bytes Binary encrypted data. Raises ------ ValueError Data length must be multiple of DES block size 8. Examples -------- >>> import psec >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> psec.des.encrypt_tdes_ecb(key, b"12345678").hex().upper() '41D2FFBA3CDC15FE' """ if len(data) < 8 or len(data) % 8 != 0: raise ValueError( f"Data length ({str(len(data))}) must be multiple of DES block size 8." ) cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) return cipher.encryptor().update(data)
def mac_iso9797_3(key1: bytes, key2: bytes, data: bytes, padding: int, length: Optional[int] = None) -> bytes: r"""ISO/IEC 9797-1 MAC algorithm 3. Requires two independent keys. Only the last data block is processed using TDES, all previous blocks are processed using single DES. Parameters ---------- key1 : bytes Binary MAC key used in initial transformation. Has to be a valid DES key. key2 : bytes Binary MAC key used in output transformation. Has to be a valid DES key. data : bytes Data to be MAC'd. padding : int Padding method of `data`. - 1 = ISO/IEC 9797-1 method 1. - 2 = ISO/IEC 9797-1 method 2. - 3 = ISO/IEC 9797-1 method 3. length : int, optional Desired length of AC [4 <= N <= 8] (default 8 bytes). Returns ------- mac : bytes Returns a binary MAC of requested length Raises ------ ValueError Invalid padding method specified Notes ----- See https://en.wikipedia.org/wiki/ISO/IEC_9797-1 for the algorithm reference. See Also -------- pyemv.mac.pad_iso9797_1 : ISO/IEC 9791-1 padding method 1 pyemv.mac.pad_iso9797_2 : ISO/IEC 9791-1 padding method 2 pyemv.mac.pad_iso9797_3 : ISO/IEC 9791-1 padding method 3 Examples -------- >>> from pyemv.mac import mac_iso9797_3 >>> key1 = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> key2 = bytes.fromhex("FEDCBA98765432100123456789ABCDEF") >>> data = bytes.fromhex("1234567890ABCDEF") >>> mac_iso9797_3(key1, key2, data, padding=2).hex().upper() '644AA5C915DBDAF8' """ if length is None: length = 8 if padding == 1: data = pad_iso9797_1(data, 8) elif padding == 2: data = pad_iso9797_2(data, 8) elif padding == 3: data = pad_iso9797_3(data, 8) else: raise ValueError("Specify valid padding method: 1, 2 or 3.") # Encrypt first block with key1 then # encrypt the rest of the data in CBC mode cipher1 = _Cipher( _algorithms.TripleDES(key1), _modes.CBC(b"\x00\x00\x00\x00\x00\x00\x00\x00"), backend=_default_backend(), ) encryptor1 = cipher1.encryptor() data = encryptor1.update(data)[-8:] # Decrypt the last block with key2 and then encrypt it with key1 cipher2 = _Cipher(_algorithms.TripleDES(key2), _modes.CBC(data), backend=_default_backend()) decryptor2 = cipher2.decryptor() return encryptor1.update(decryptor2.update(data))[:length]
def generate_retail_mac( key1: bytes, key2: bytes, data: bytes, padding: int, length: _typing.Optional[int] = None, ) -> bytes: r"""ISO/IEC 9797-1 MAC algorithm 3 aka retail MAC. Requires two independent keys. All blocks until the last are processed using single DES using key1. The last data block is processed using TDES using key2 and key1. The resulting block is the MAC. Parameters ---------- key1 : bytes Binary MAC key used in initial transformation. Has to be a valid DES key. key2 : bytes Binary MAC key used in output transformation. Has to be a valid DES key. data : bytes Data to be MAC'd. padding : int Padding method of `data`. - 1 = ISO/IEC 9797-1 method 1. - 2 = ISO/IEC 9797-1 method 2. - 3 = ISO/IEC 9797-1 method 3. length : int, optional Desired MAC length [4 <= N <= 8] (default 8 bytes). Returns ------- mac : bytes Returns a binary MAC of requested length Raises ------ ValueError Invalid padding method specified Notes ----- See https://en.wikipedia.org/wiki/ISO/IEC_9797-1 for the algorithm reference. See Also -------- psec.mac.pad_iso_1 : ISO/IEC 9791-1 padding method 1 psec.mac.pad_iso_2 : ISO/IEC 9791-1 padding method 2 psec.mac.pad_iso_3 : ISO/IEC 9791-1 padding method 3 Examples -------- >>> import psec >>> key1 = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> key2 = bytes.fromhex("FEDCBA98765432100123456789ABCDEF") >>> data = bytes.fromhex("1234567890ABCDEF") >>> psec.mac.generate_retail_mac(key1, key2, data, padding=2).hex().upper() '644AA5C915DBDAF8' """ if length is None: length = 8 try: data = _pad_dispatch[padding](data, 8) except KeyError: raise ValueError("Specify valid padding method: 1, 2 or 3.") # Encrypt first block with key1 then # encrypt the rest of the data in CBC mode cipher1 = _Cipher( _algorithms.TripleDES(key1), _modes.CBC(b"\x00\x00\x00\x00\x00\x00\x00\x00"), backend=_default_backend(), ) encryptor1 = cipher1.encryptor() data = encryptor1.update(data)[-8:] # Decrypt the last block with key2 and then encrypt it with key1 cipher2 = _Cipher( _algorithms.TripleDES(key2), _modes.CBC(data), backend=_default_backend() ) decryptor2 = cipher2.decryptor() return encryptor1.update(decryptor2.update(data))[:length]