def decode_with_ssh_key(key_path: str, encoded_string: str) -> str: """ decrypts a plain string using some data from key file :param key_path: path to key file :param encoded_string: text that has to be decrypted :return: decrypted text """ key, iv = get_key_and_iv(key_path) encrypted_bytes = base64.b64decode(encoded_string) try: from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend backend = default_backend() cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=backend) decryptor = cipher.decryptor() decrypted_bytes = decryptor.update( encrypted_bytes) + decryptor.finalize() except ModuleNotFoundError: import Crypto.PublicKey.RSA # used for generating ssh key import Crypto.Cipher.AES cipher = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_CFB, iv) decrypted_bytes = cipher.decrypt(encrypted_bytes) return decrypted_bytes.decode()
def main(): filetxt = '' with open('file.txt', 'r') as f: # for i in f: # filetxt+= i.strip('\n').strip('\r') filetxt = f.read() # print(filetxt) ############################## Using cryptography library ################################### filetxt = bytes.fromhex(base64.b64decode(filetxt).hex()) key = b'YELLOW SUBMARINE' hexkey = binascii.hexlify(key) # print(hexkey) cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) encryptor = cipher.encryptor() ### Test ### ct = encryptor.update(b"a secret message") + encryptor.finalize() # print(ct) ############ decryptor = cipher.decryptor() result = decryptor.update(filetxt) + decryptor.finalize() print(result.decode()) ############################################################################################### ############################## Using Crypto.cipher library ################################### cipher = AES.new(key, AES.MODE_ECB) print(cipher.decrypt(filetxt).decode())
def RunBlockCipher2(self, message_byte_array, n_runs, key): '''Implemented as using Blowfish symmetric block cipher. Runs the second block cipher to assess performance. Returns nothing.''' for i in range(n_runs): ########### # Run cryptography library implementation self.DisplayCipherStart("cryptography", "Blowfish", i) startTime = time.time() blockLength = 8 IV = os.urandom(blockLength) blowfish = Cipher(algorithms.Blowfish(key), modes.CBC(IV), default_backend()) blowfishEncryptor = blowfish.encryptor() blowfishDecryptor = blowfish.decryptor() paddedMessage = self.AddPadding(message_byte_array, blockLength) splitMessage = self.SplitMessage(paddedMessage, 500 * blockLength) unpaddedMessage = bytearray() for segment in splitMessage: unpaddedSegment = self.RemovePadding(blowfishDecryptor.update(blowfishEncryptor.update(segment)), blockLength) unpaddedMessage.extend(unpaddedSegment) endTime = time.time() # If output of the algorithm is desired, uncomment the line below #BinaryFileHandler.WriteByteDataFile("cryptographyoutputblowfish." + message_filename.split('.')[1]) self.cryptographyTimeResults[self.blockCipher2].append(endTime - startTime) self.DisplayCipherEnd("cryptography", "Blowfish", i) ############## # Run PyCrypto library implementation self.DisplayCipherStart("PyCrypto", "Blowfish", i) startTime = time.time() blockLength = 8 IV = os.urandom(blockLength) blowfish = Crypto.Cipher.Blowfish.new(key, mode=Crypto.Cipher.blockalgo.MODE_CBC, IV=IV) self.AddPadding(message_byte_array, blockLength) extendedMessage = bytearray(IV) extendedMessage.extend(paddedMessage) encryptedMessage = blowfish.encrypt(bytes(extendedMessage)) decryptedMessage = blowfish.decrypt(encryptedMessage) unpaddedMessage = self.RemovePadding(decryptedMessage[blockLength:], blockLength) endTime = time.time() # If output of the algorithm is desired, uncomment the line below #BinaryFileHandler.WriteByteDataFile("PyCryptooutputblowfish." + message_filename.split('.')[1]) self.PyCryptoTimeResults[self.blockCipher2].append(endTime - startTime) self.DisplayCipherEnd("PyCrypto", "Blowfish", i)
def RunStreamCipher2(self, message_byte_array, n_runs, key): '''Implemented as using AES (Advanced Encryption Standard) symmetric cipher in CTR (Counter) mode which allows it to run as a stream cipher. The key is 192 bits (24 bytes). Runs the second stream cipher to assess performance. Returns nothing.''' for i in range(n_runs): ######## # Run cryptography library implementation self.DisplayCipherStart("cryptography", "AES (CTR)", i) startTime = time.time() blockLength = 16 IV = os.urandom(blockLength) aes = Cipher(algorithms.AES(key), modes.CTR(IV), default_backend()) paddedMessage = self.AddPadding(message_byte_array, blockLength) splitMessage = self.SplitMessage(paddedMessage, 500 * blockLength) unpaddedMessage = self.RunCryptographyAndUnpadSplitMessage(splitMessage, aes, blockLength) endTime = time.time() # If output of the algorithm is desired, uncomment the line below #BinaryFileHandler.WriteByteDataFile("cryptographyoutputaes." + message_filename.split('.')[1]) self.cryptographyTimeResults[self.streamCipher2].append(endTime - startTime) self.DisplayCipherEnd("cryptography", "AES (CTR)", i) ########## # Run PyCrypto library implementation self.DisplayCipherStart("PyCrypto", "AES (CTR)", i) startTime = time.time() blockLength = 16 IV = os.urandom(blockLength) # AES in CTR mode for the PyCrypto library requires a counter instead # of an initialization vector aes = Crypto.Cipher.AES.new(key, mode=Crypto.Cipher.blockalgo.MODE_CTR, counter=Crypto.Util.Counter.new(128)) paddedMessage = self.AddPadding(message_byte_array, blockLength) encryptedMessage = aes.encrypt(bytes(paddedMessage)) decryptedMessage = aes.decrypt(encryptedMessage) unpaddedMessage = self.RemovePadding(decryptedMessage[blockLength:], blockLength) endTime = time.time() # If output of the algorithm is desired, uncomment the line below #BinaryFileHandler.WriteByteDataFile("PyCryptooutputaes." + message_filename.split('.')[1]) self.PyCryptoTimeResults[self.streamCipher2].append(endTime - startTime) self.DisplayCipherEnd("PyCrypto", "AES (CTR)", i)
def RunStreamCipher1(self, message_byte_array, n_runs, key): '''Implemented as using ARC4 symmetric block cipher using 192 bits (24 bytes). Runs the first stream cipher to assess performance. Returns nothing.''' for i in range(n_runs): ######## # Run cryptography library implementation self.DisplayCipherStart("cryptography", "ARC4", i) startTime = time.time() arc4 = Cipher(algorithms.ARC4(key), None, default_backend()) arc4Encryptor = arc4.encryptor() arc4Decryptor = arc4.decryptor() splitMessage = self.SplitMessage(message_byte_array, 8000) unpaddedMessage = bytearray() for segment in splitMessage: unpaddedSegment = arc4Decryptor.update(arc4Encryptor.update(segment)) unpaddedMessage.extend(unpaddedSegment) endTime = time.time() # If output of the algorithm is desired, uncomment the line below #BinaryFileHandler.WriteByteDataFile("cryptographyoutputarc4." + message_filename.split('.')[1]) self.cryptographyTimeResults[self.streamCipher1].append(endTime - startTime) self.DisplayCipherEnd("cryptography", "ARC4", i) ########### # Run PyCrypto library implementation self.DisplayCipherStart("PyCrypto", "ARC4", i) startTime = time.time() arc4 = Crypto.Cipher.ARC4.new(key) encryptedMessage = arc4.encrypt(message_byte_array) decryptedMessage = arc4.decrypt(encryptedMessage) endTime = time.time() # If output of the algorithm is desired, uncomment the line below #BinaryFileHandler.WriteByteDataFile("PyCryptooutputarc4." + message_filename.split('.')[1]) self.PyCryptoTimeResults[self.streamCipher1].append(endTime - startTime) self.DisplayCipherEnd("PyCrypto", "ARC4", i)
class _AEADCipher(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") tests correspond to the legacy API of the crypto library. With cryptography v2.0, both CCM and GCM should follow the else case. Note that the "fixed_iv" in TLS RFCs is called "salt" in the AEAD RFC 5116. """ type = "aead" fixed_iv_len = 4 nonce_explicit_len = 8 def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings, whereas the internal 'nonce_explicit' is an integer (it is simpler for incrementation). /!\ The whole 'nonce' may be called IV in certain RFCs. """ self.ready = {"key": True, "fixed_iv": True, "nonce_explicit": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len if nonce_explicit is None: self.ready["nonce_explicit"] = False nonce_explicit = 0 if isinstance(nonce_explicit, str): nonce_explicit = pkcs_os2ip(nonce_explicit) # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher, self).__setattr__("key", key) super(_AEADCipher, self).__setattr__("fixed_iv", fixed_iv) super(_AEADCipher, self).__setattr__("nonce_explicit", nonce_explicit) if hasattr(self, "pc_cls"): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(self._get_nonce()), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True elif name == "nonce_explicit": if isinstance(val, str): val = pkcs_os2ip(val) self.ready["nonce_explicit"] = True super(_AEADCipher, self).__setattr__(name, val) def _get_nonce(self): return (self.fixed_iv + pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len)) def _update_nonce_explicit(self): """ Increment the explicit nonce while avoiding any overflow. """ ne = self.nonce_explicit + 1 self.nonce_explicit = ne % 2**(self.nonce_explicit_len * 8) def auth_encrypt(self, P, A, seq_num=None): """ Encrypt the data then prepend the explicit part of the nonce. The authentication tag is directly appended with the most recent crypto API. Additional data may be authenticated without encryption (as A). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = None encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if isinstance(self._cipher, AESCCM): res = self._cipher.encrypt(self._get_nonce(), P, A, tag_length=self.tag_len) else: res = self._cipher.encrypt(self._get_nonce(), P, A) nonce_explicit = pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len) self._update_nonce_explicit() return nonce_explicit + res def auth_decrypt(self, A, C, seq_num=None, add_length=True): """ Decrypt the data and authenticate the associated data (i.e. A). If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. Note that we add the TLSCiphertext length to A although we're supposed to add the TLSCompressed length. Fortunately, they are the same, but the specifications actually messed up here. :'( The 'add_length' switch should always be True for TLS, but we provide it anyway (mostly for test cases, hum). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ nonce_explicit_str, C, mac = (C[:self.nonce_explicit_len], C[self.nonce_explicit_len:-self.tag_len], C[-self.tag_len:]) if False in six.itervalues(self.ready): raise CipherError(nonce_explicit_str, C, mac) self.nonce_explicit = pkcs_os2ip(nonce_explicit_str) if add_length: A += struct.pack("!H", len(C)) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(nonce_explicit_str, P, mac) else: try: if isinstance(self._cipher, AESCCM): P = self._cipher.decrypt(self._get_nonce(), C + mac, A, tag_length=self.tag_len) else: P = self._cipher.decrypt(self._get_nonce(), C + mac, A) except InvalidTag: raise AEADTagError(nonce_explicit_str, "<unauthenticated data>", mac) return nonce_explicit_str, P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv, self.nonce_explicit) c.ready = self.ready.copy() return c
class _AEADCipher_TLS13(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") enable support for the legacy implementation of GCM in the cryptography library. They should not be used, and might eventually be removed, with cryptography v2.0. XXX """ type = "aead" def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings. This IV never changes: it is either the client_write_IV or server_write_IV. Note that 'nonce_explicit' is never used. It is only a safeguard for a call in session.py to the TLS 1.2/ChaCha20Poly1305 case (see RFC 7905). """ self.ready = {"key": True, "fixed_iv": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher_TLS13, self).__setattr__("key", key) super(_AEADCipher_TLS13, self).__setattr__("fixed_iv", fixed_iv) if hasattr(self, "pc_cls"): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(fixed_iv), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True super(_AEADCipher_TLS13, self).__setattr__(name, val) def _get_nonce(self, seq_num): padlen = self.fixed_iv_len - len(seq_num) padded_seq_num = b"\x00" * padlen + seq_num return strxor(padded_seq_num, self.fixed_iv) def auth_encrypt(self, P, A, seq_num): """ Encrypt the data, and append the computed authentication code. TLS 1.3 does not use additional data, but we leave this option to the user nonetheless. Note that the cipher's authentication tag must be None when encrypting. """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._tag = None self._cipher.mode._initialization_vector = self._get_nonce(seq_num) encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): res = self._cipher.encrypt(self._get_nonce(seq_num), P, A, tag_length=self.tag_len) else: res = self._cipher.encrypt(self._get_nonce(seq_num), P, A) return res def auth_decrypt(self, A, C, seq_num): """ Decrypt the data and verify the authentication code (in this order). Note that TLS 1.3 is not supposed to use any additional data A. If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. """ C, mac = C[:-self.tag_len], C[-self.tag_len:] if False in six.itervalues(self.ready): raise CipherError(C, mac) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce(seq_num) self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(P, mac) else: try: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A, tag_length=self.tag_len) else: if (conf.crypto_valid_advanced and isinstance(self, Cipher_CHACHA20_POLY1305)): A += struct.pack("!H", len(C)) P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) except InvalidTag: raise AEADTagError("<unauthenticated data>", mac) return P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv) c.ready = self.ready.copy() return c
class SSLWrapper: """ """ def __init__(self, password): if not HAS_CRYPTOLIB: raise ImportError( 'M2Crypto, PyCrypto or cryptography is not installed') self._cipher = None self._password = None if password is None: raise Exception('Password should not be Empty') else: self._password = password def update(self, chunk): if self._cipher is None: if len(chunk) < 16: raise Exception('Invalid first chunk (Size < 16).') if chunk[0:8] != b"Salted__": raise Exception('Invalid first chunk (expected: Salted__') [key, iv] = self._get_key_iv(self._password, chunk[8:16]) if HAS_M2CRYPTO: self._cipher = EVP.Cipher('des_cbc', key, iv, 0) elif HAS_CRYPTOGRAPHY: self._cipher = Cipher(algorithms.TripleDES(key), modes.CBC(iv), backend=default_backend()).decryptor() else: self._cipher = DES.new(key, DES.MODE_CBC, iv) chunk = chunk[16:] if len(chunk) > 0: if HAS_M2CRYPTO: return self._cipher.update(chunk) elif HAS_CRYPTOGRAPHY: return self._cipher.update(chunk) else: return self._cipher.decrypt(chunk) else: return b"" def final(self): if self._cipher is None: raise Exception('Wrapper has not started yet.') if HAS_M2CRYPTO: return self._cipher.final() elif HAS_CRYPTOGRAPHY: return self._cipher.finalize() else: return b"" def _get_key_iv(self, password, salt=None, size=8): # make sure password is a string and not unicode password = password.encode('utf-8') chunk = None key = b"" iv = b"" while True: hash = hashlib.md5() if (chunk is not None): hash.update(chunk) hash.update(password) if (salt is not None): hash.update(salt) chunk = hash.digest() i = 0 if len(key) < size: i = min(size - len(key), len(chunk)) key += chunk[0:i] if len(iv) < size and i < len(chunk): j = min(size - len(iv), len(chunk) - i) iv += chunk[i:i + j] if (len(key) == size and len(iv) == size): break return [key, iv]
class _AEADCipher(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") tests correspond to the legacy API of the crypto library. With cryptography v2.0, both CCM and GCM should follow the else case. Note that the "fixed_iv" in TLS RFCs is called "salt" in the AEAD RFC 5116. """ type = "aead" fixed_iv_len = 4 nonce_explicit_len = 8 def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings, whereas the internal # noqa: E501 'nonce_explicit' is an integer (it is simpler for incrementation). /!\ The whole 'nonce' may be called IV in certain RFCs. """ self.ready = {"key": True, "fixed_iv": True, "nonce_explicit": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len if nonce_explicit is None: self.ready["nonce_explicit"] = False nonce_explicit = 0 if isinstance(nonce_explicit, str): nonce_explicit = pkcs_os2ip(nonce_explicit) # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher, self).__setattr__("key", key) super(_AEADCipher, self).__setattr__("fixed_iv", fixed_iv) super(_AEADCipher, self).__setattr__("nonce_explicit", nonce_explicit) if hasattr(self, "pc_cls"): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(self._get_nonce()), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True elif name == "nonce_explicit": if isinstance(val, str): val = pkcs_os2ip(val) self.ready["nonce_explicit"] = True super(_AEADCipher, self).__setattr__(name, val) def _get_nonce(self): return (self.fixed_iv + pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len)) def _update_nonce_explicit(self): """ Increment the explicit nonce while avoiding any overflow. """ ne = self.nonce_explicit + 1 self.nonce_explicit = ne % 2**(self.nonce_explicit_len * 8) def auth_encrypt(self, P, A, seq_num=None): """ Encrypt the data then prepend the explicit part of the nonce. The authentication tag is directly appended with the most recent crypto API. Additional data may be authenticated without encryption (as A). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = None encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if isinstance(self._cipher, AESCCM): res = self._cipher.encrypt(self._get_nonce(), P, A, tag_length=self.tag_len) else: res = self._cipher.encrypt(self._get_nonce(), P, A) nonce_explicit = pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len) self._update_nonce_explicit() return nonce_explicit + res def auth_decrypt(self, A, C, seq_num=None, add_length=True): """ Decrypt the data and authenticate the associated data (i.e. A). If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. Note that we add the TLSCiphertext length to A although we're supposed to add the TLSCompressed length. Fortunately, they are the same, but the specifications actually messed up here. :'( The 'add_length' switch should always be True for TLS, but we provide it anyway (mostly for test cases, hum). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ nonce_explicit_str, C, mac = (C[:self.nonce_explicit_len], C[self.nonce_explicit_len:-self.tag_len], C[-self.tag_len:]) if False in six.itervalues(self.ready): raise CipherError(nonce_explicit_str, C, mac) self.nonce_explicit = pkcs_os2ip(nonce_explicit_str) if add_length: A += struct.pack("!H", len(C)) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(nonce_explicit_str, P, mac) else: try: if isinstance(self._cipher, AESCCM): P = self._cipher.decrypt(self._get_nonce(), C + mac, A, tag_length=self.tag_len) else: P = self._cipher.decrypt(self._get_nonce(), C + mac, A) except InvalidTag: raise AEADTagError(nonce_explicit_str, "<unauthenticated data>", mac) return nonce_explicit_str, P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv, self.nonce_explicit) c.ready = self.ready.copy() return c
class _AEADCipher_TLS13(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") enable support for the legacy implementation of GCM in the cryptography library. They should not be used, and might eventually be removed, with cryptography v2.0. XXX """ type = "aead" def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings. This IV never changes: it is either the client_write_IV or server_write_IV. Note that 'nonce_explicit' is never used. It is only a safeguard for a call in session.py to the TLS 1.2/ChaCha20Poly1305 case (see RFC 7905). """ self.ready = {"key": True, "fixed_iv": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher_TLS13, self).__setattr__("key", key) super(_AEADCipher_TLS13, self).__setattr__("fixed_iv", fixed_iv) if hasattr(self, "pc_cls"): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(fixed_iv), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True super(_AEADCipher_TLS13, self).__setattr__(name, val) def _get_nonce(self, seq_num): padlen = self.fixed_iv_len - len(seq_num) padded_seq_num = b"\x00" * padlen + seq_num return strxor(padded_seq_num, self.fixed_iv) def auth_encrypt(self, P, A, seq_num): """ Encrypt the data, and append the computed authentication code. TLS 1.3 does not use additional data, but we leave this option to the user nonetheless. Note that the cipher's authentication tag must be None when encrypting. """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._tag = None self._cipher.mode._initialization_vector = self._get_nonce(seq_num) encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): res = self._cipher.encrypt(self._get_nonce(seq_num), P, A, tag_length=self.tag_len) else: res = self._cipher.encrypt(self._get_nonce(seq_num), P, A) return res def auth_decrypt(self, A, C, seq_num): """ Decrypt the data and verify the authentication code (in this order). Note that TLS 1.3 is not supposed to use any additional data A. If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. """ C, mac = C[:-self.tag_len], C[-self.tag_len:] if False in six.itervalues(self.ready): raise CipherError(C, mac) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce(seq_num) self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(P, mac) else: try: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A, # noqa: E501 tag_length=self.tag_len) else: if (conf.crypto_valid_advanced and isinstance(self, Cipher_CHACHA20_POLY1305)): A += struct.pack("!H", len(C)) P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) # noqa: E501 except InvalidTag: raise AEADTagError("<unauthenticated data>", mac) return P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv) c.ready = self.ready.copy() return c