def hash_password(password, iterations, algorithm="pbkdf2hmac", sub_algorithm="sha256", salt=None, salt_size=16, output_size=32, backend=BACKEND): salt = os.urandom(salt_size) if salt is None else salt header = save_data(algorithm, sub_algorithm, iterations, salt_size, output_size) if algorithm == "pbkdf2hmac": hasher = PBKDF2HMAC(algorithm=getattr(hashes, sub_algorithm.upper())(), length=output_size, salt=salt, iterations=iterations, backend=backend) return save_data(header, salt, hasher.derive(header + password)) else: raise ValueError()
def decrypt(packed_encrypted_data, key, mac_key='', backend=BACKEND): """ Decrypts packed encrypted data as returned by encrypt with the same key. If extra data is present, returns plaintext, extra_data. If not, returns plaintext. Raises InvalidTag on authentication failure. """ header, ciphertext, iv, tag, extra_data = load_data( packed_encrypted_data) algorithm, mode, authentication_algorithm = header.split('_', 2) if algorithm.lower() in hashlib.algorithms_guaranteed: return cryptographyless.decrypt(packed_encrypted_data, key, mac_key, backend) mode_args = (iv, tag) if mode in AEAD_MODES else (iv, ) decryptor = Cipher(getattr(algorithms, algorithm)(key), getattr(modes, mode)(*mode_args), backend=BACKEND).decryptor() if mode in AEAD_MODES: decryptor.authenticate_additional_data(extra_data) else: if not mac_key: raise ValueError( "mac_key not supplied for {} mode".format(header)) if not verify_mac( mac_key, save_data(tag, header + ciphertext + iv + extra_data), authentication_algorithm): raise InvalidTag("Failed to authenticate data") plaintext = decryptor.update(ciphertext) + decryptor.finalize() if extra_data: return (plaintext, extra_data) else: return plaintext
def decrypt(packed_encrypted_data, key, mac_key='', backend=BACKEND): """ Decrypts packed encrypted data as returned by encrypt with the same key. If extra data is present, returns plaintext, extra_data. If not, returns plaintext. Raises InvalidTag on authentication failure. """ header, ciphertext, iv, tag, extra_data = load_data(packed_encrypted_data) algorithm, mode, authentication_algorithm = header.split('_', 2) if algorithm.lower() in hashlib.algorithms_guaranteed: return cryptographyless.decrypt(packed_encrypted_data, key, mac_key, backend) mode_args = (iv, tag) if mode in AEAD_MODES else (iv, ) decryptor = Cipher(getattr(algorithms, algorithm)(key), getattr(modes, mode)(*mode_args), backend=BACKEND).decryptor() if mode in AEAD_MODES: decryptor.authenticate_additional_data(extra_data) else: if not mac_key: raise ValueError("mac_key not supplied for {} mode".format(header)) if not verify_mac(mac_key, save_data(tag, header + ciphertext + iv + extra_data), authentication_algorithm): raise InvalidTag("Failed to authenticate data") plaintext = decryptor.update(ciphertext) + decryptor.finalize() if extra_data: return (plaintext, extra_data) else: return plaintext
def encrypt(data='', key='', mac_key='', iv=None, extra_data='', algorithm="AES", mode="GCM", backend=BACKEND, iv_size=16, hash_algorithm="SHA256", return_mode="cryptogram"): """ Encrypts data with the specified key. Returns packed encrypted bytes. If an iv is not supplied a random one of iv_size will be generated. By default, the GCM mode of operation is used and the iv is automatically included in the extra_data authenticated by the mode. Note that not all algorithms may support all modes of operation with all backends. A mac key is required when GCM mode is not in used. This function will refuse to encrypt data without authentication/integrity checks, as this is considered a serious flaw in security. Technically speaking, 'iv' is not always the correct term for the parameter passed, depending on the mode of operation used. However, using two different fields for what are functionally the same would increase complexity needlessly. """ assert data and key, "data" if not data else "key" if algorithm.lower() in hashlib.algorithms_guaranteed: return cryptographyless.encrypt(data, key, iv, extra_data, algorithm, mode, backend, iv_size, mac_key, hash_algorithm) header = algorithm + '_' + mode if mode not in AEAD_MODES: if not mac_key: raise ValueError("Unable to authenticate data because no mac key was supplied for {} mode".format(header)) else: header += "_" + hash_algorithm else: header += "_" + "AEAD" if not iv and iv != 0: # 0 is a valid nonce for CTR mode. iv = random_bytes(iv_size) if mode != "ECB": mode_args = (iv, ) else: mode_args = tuple() encryptor = Cipher(getattr(algorithms, algorithm)(key), getattr(modes, mode)(*mode_args), backend=BACKEND).encryptor() if mode in AEAD_MODES: encryptor.authenticate_additional_data(extra_data) ciphertext = encryptor.update(data) + encryptor.finalize() if mode in AEAD_MODES: mac_tag = encryptor.tag else: mac_tag = generate_mac(mac_key, header + ciphertext + iv + extra_data, hash_algorithm) if return_mode == "cryptogram": return save_data(header, ciphertext, iv, mac_tag, extra_data) else: assert return_mode == "values" return header, ciphertext, iv, mac_tag, extra_data
def save(self, _file=None): """ usage: base_object.save(_file=None) Saves the state of the calling objects __dict__. If _file is not specified, a serialized stream is returned. If _file is specified, the stream is written to the supplied file like object and then returned. This method and load are being reimplemented""" raise NotImplementedError() self.alert("Saving", level=self.verbosity["save"]) attributes = self.__getstate__() self_objects = attributes.pop("objects", {}) saved_objects = attributes["objects"] = {} found_objects = [] for component_type, values in self_objects.items(): saved_objects[component_type] = new_values = [] for value in sorted(values, key=operator.attrgetter("reference")): if hasattr(value, "save"): found_objects.append(value) if not getattr(value, "dont_save", False): new_values.append(value.save()) attribute_type = attributes["_attribute_type"] = {} for key, value in attributes.items(): if value in found_objects: attributes[key] = value.reference attribute_type[key] = "reference" elif hasattr(value, "save") and not getattr(value, "dont_save"): attributes[key] = value.save() attribute_type[key] = "saved" #required_modules = pride.functions.module_utilities.get_all_modules_for_class(type(self)) #version_control = objects["/Program/Version_Control"] #user = objects["/User"] #hash_function = user.generate_tag #repo_id = hash_function(user.username) #_required_modules = [] #for module_name, source, module_object in required_modules: #module_id = hash_function(source) #version_control.save_module(module_name, source, module_id, repo_id) #_required_modules.append(module_name) #attributes["_required_modules"] = _required_modules + [self.__class__.__name__] attributes["_type_info"] = (self.__module__, self.__class__.__name__) #try: # saved_data = pride.objects["/User"].save_data(attributes) #except TypeError: # self.alert("Unable to save attributes '{}'".format(pprint.pformat(attributes)), level=0) # raise saved_data = utilities.save_data(attributes) if _file: _file.write(saved_data) return saved_data
def save(self, _file=None): """ usage: base_object.save(_file=None) Saves the state of the calling objects __dict__. If _file is not specified, a serialized stream is returned. If _file is specified, the stream is written to the supplied file like object and then returned. This method and load are being reimplemented""" self.alert("Saving", level=self.verbosity["save"]) attributes = self.__getstate__() self_objects = attributes.pop("objects", {}) saved_objects = attributes["objects"] = {} found_objects = [] for component_type, values in self_objects.items(): saved_objects[component_type] = new_values = [] for value in sorted(values, key=operator.attrgetter("reference")): if hasattr(value, "save"): found_objects.append(value) if not getattr(value, "dont_save", False): new_values.append(value.save()) attribute_type = attributes["_attribute_type"] = {} for key, value in attributes.items(): if value in found_objects: attributes[key] = value.reference attribute_type[key] = "reference" elif hasattr(value, "save") and not getattr(value, "dont_save"): attributes[key] = value.save() attribute_type[key] = "saved" #required_modules = pride.functions.module_utilities.get_all_modules_for_class(type(self)) #version_control = objects["/Python/Version_Control"] #user = objects["/User"] #hash_function = user.generate_tag #repo_id = hash_function(user.username) #_required_modules = [] #for module_name, source, module_object in required_modules: #module_id = hash_function(source) #version_control.save_module(module_name, source, module_id, repo_id) #_required_modules.append(module_name) #attributes["_required_modules"] = _required_modules + [self.__class__.__name__] attributes["_type_info"] = (self.__module__, self.__class__.__name__) #try: # saved_data = pride.objects["/User"].save_data(attributes) #except TypeError: # self.alert("Unable to save attributes '{}'".format(pprint.pformat(attributes)), level=0) # raise saved_data = utilities.save_data(attributes) if _file: _file.write(saved_data) return saved_data
def apply_mac(key, data, algorithm="SHA256", backend=BACKEND): """ Generates a message authentication code and prepends it to data. Mac and data are packed via pride.functions.utilities.save_data. Applying a message authentication code facilitates the goals of authenticity and integrity. Note it does not protect confidentiality (i.e. encryption). Combining a mac with encryption is NOT straightforward; Authenticating/providing integrity of confidential data should preferably be accomplished via an appropriate block cipher mode of operation, such as GCM. If this is not possible, encrypt-then-mac is most secure solution in general. """ return save_data(generate_mac(key, data, algorithm, backend), data)
def encrypt(data='', key='', mac_key='', iv=None, extra_data='', algorithm="AES", mode="GCM", backend=BACKEND, iv_size=16, hash_algorithm="SHA256", return_mode="cryptogram"): """ Encrypts data with the specified key. Returns packed encrypted bytes. If an iv is not supplied a random one of iv_size will be generated. By default, the GCM mode of operation is used and the iv is automatically included in the extra_data authenticated by the mode. Note that not all algorithms may support all modes of operation with all backends. A mac key is required when GCM mode is not in used. This function will refuse to encrypt data without authentication/integrity checks, as this is considered a serious flaw in security. Technically speaking, 'iv' is not always the correct term for the parameter passed, depending on the mode of operation used. However, using two different fields for what are functionally the same would increase complexity needlessly. """ assert data and key, "data" if not data else "key" if algorithm.lower() in hashlib.algorithms_guaranteed: return cryptographyless.encrypt(data, key, iv, extra_data, algorithm, mode, backend, iv_size, mac_key, hash_algorithm) header = algorithm + '_' + mode if mode not in AEAD_MODES: if not mac_key: raise ValueError( "Unable to authenticate data because no mac key was supplied for {} mode" .format(header)) else: header += "_" + hash_algorithm else: header += "_" + "AEAD" if not iv and iv != 0: # 0 is a valid nonce for CTR mode. iv = random_bytes(iv_size) if mode != "ECB": mode_args = (iv, ) else: mode_args = tuple() encryptor = Cipher(getattr(algorithms, algorithm)(key), getattr(modes, mode)(*mode_args), backend=BACKEND).encryptor() if mode in AEAD_MODES: encryptor.authenticate_additional_data(extra_data) ciphertext = encryptor.update(data) + encryptor.finalize() if mode in AEAD_MODES: mac_tag = encryptor.tag else: mac_tag = generate_mac(mac_key, header + ciphertext + iv + extra_data, hash_algorithm) if return_mode == "cryptogram": return save_data(header, ciphertext, iv, mac_tag, extra_data) else: assert return_mode == "values" return header, ciphertext, iv, mac_tag, extra_data