Файловый менеджер - Редактировать - /var/opt/nydus/ops/primordial/encryptor.py
Назад
# -*- coding: utf-8 -*- import hashlib import json import os from base64 import b64decode, b64encode from pathlib import Path from typing import AnyStr, Optional, Union, cast from cryptography import x509 from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP from oscrypto.symmetric import aes_cbc_pkcs7_encrypt, aes_cbc_pkcs7_decrypt def _make_bytes(data: AnyStr) -> bytes: """ Convert a Python `str` object to a `bytes` object. If the parameter is already a `bytes` object, return it unmodified. :param data: The object to be converted :return: The converted object, or the original object if it was not a `str` object """ if isinstance(data, str): data = data.encode("utf-8") # type: ignore return cast(bytes, data) def load_key_content(key_path: Union[Path, str]) -> bytes: """ Convenience function to load the content of a key or cert file and return its contents. :param key_path: Path to the key/cert file to be loaded :return: The file contents as a bytes object :raises: ValueError if the key_path parameter is None of doesn't point to an existing file """ if key_path is None: raise ValueError("key_path parameter cannot be None") if isinstance(key_path, str): key_path = Path(key_path) if not key_path.is_file(): raise ValueError("key path '{key_path}' does not exist".format(key_path=key_path)) return key_path.read_bytes() class Encryptor: __iv_size = 16 # iv -> Initialization Vector @classmethod def decrypt(cls, encrypted_data: AnyStr, secret_key: AnyStr) -> str: """ Decrypt encrypted data using the PKCS7 symmetric decryption algorithm :param encrypted_data: Base-64 encoded byte array containing encrypted data, which is a combination of the salt and the actual data :param secret_key: Secret value used to generate an encryption key :return: Decrypted, plain text value """ decoded_data = b64decode(_make_bytes(encrypted_data)) iv = decoded_data[:cls.__iv_size] data = decoded_data[cls.__iv_size:] secret_key_bytes = _make_bytes(secret_key) hashed_secret_key = hashlib.sha256(secret_key_bytes).digest() return aes_cbc_pkcs7_decrypt(hashed_secret_key, data, iv).decode("utf-8") @classmethod def encrypt(cls, unencrypted_data: AnyStr, secret_key: AnyStr) -> bytes: """ Encrypts data using the PKCS7 symmetric encryption algorithm :param unencrypted_data: Data to be encrypted :param secret_key: Secret value used to generate an encryption key :return: Base-64 encoded byte array containing encrypted value """ iv_bytes = os.urandom(cls.__iv_size) plain_text_bytes = _make_bytes(unencrypted_data) secret_key_bytes = _make_bytes(secret_key) hashed_secret_key = hashlib.sha256(secret_key_bytes).digest() iv, encrypted_data = aes_cbc_pkcs7_encrypt(hashed_secret_key, plain_text_bytes, iv_bytes) return b64encode(iv + encrypted_data) class SmallPayloadEncryptor: """ Utility class that provides methods to encrypt and decrypt small-ish payloads via an asymmetric (public/private key) algorithm. The definition of "small" depends on the size of the encryption key and the type of padding algorithm used. For example, given a key size of 4096 bytes and the type of padding used by this set class, the maximum size of a payload that can be encrypted is 447 bytes. """ __hash_algorithm = hashes.SHA256() __padding = OAEP(mgf=MGF1(algorithm=__hash_algorithm), algorithm=__hash_algorithm, label=None) @classmethod def decrypt(cls, encrypted_data: AnyStr, decryption_key_content: bytes) -> Optional[str]: """ Decrypts data encrypted by the `encrypt()` method in this class. :param encrypted_data: The data to be decrypted :param decryption_key_content: The content of the OpenSSL private key file corresponding to the public cert used to encrypt the data :return: The decrypted data :raises: ValueError if decryption_key_content` is None """ if encrypted_data is None: return None if decryption_key_content is None: raise ValueError("decryption_key_content can't be None") encrypted_data = b64decode(_make_bytes(encrypted_data)) # type: ignore decryption_key = serialization.load_pem_private_key(decryption_key_content, password=None) return decryption_key.decrypt(encrypted_data, cls.__padding).decode("utf-8") # type: ignore @classmethod def encrypt(cls, unencrypted_data: AnyStr, encryption_key_content: bytes) -> Optional[bytes]: """ Encrypts any small payload using an RSA asymmetric key algorithm. The maximum size of the payload depends on the size of the encryption key. For example, given a key size of 4096 bits, the maximum size of the payload that can be encrypted is 447 bytes. :param unencrypted_data: The data to be encrypted :param encryption_key_content: The content of the OpenSSL X509 public certificate that will be used to encrypt the data :return: The base64 encoded and encrypted data as a bytes object :raises: ValueError if the payload size is too large :raises: ValueError if `encryption_key_content` is None """ if unencrypted_data is None: return None if encryption_key_content is None: raise ValueError("encryption_key_content can't be None") unencrypted_data = _make_bytes(unencrypted_data) # type: ignore encryption_cert = x509.load_pem_x509_certificate(encryption_key_content) encryption_key = encryption_cert.public_key() return b64encode(encryption_key.encrypt(unencrypted_data, cls.__padding)) # type: ignore class LargePayloadEncryptor: """ This class provides methods to encrypt and decrypt large payloads via the Fernet symmetric encryption algorithm. The `encrypt()` method automatically generates a key for encryption. That key is then encrypted using the asymmetric public/private key algorithm of the `SmallPayloadEncrypter.encrypt()` method and is included in the resulting byte stream returned by this classes' `encrypt()` method. The "receiving" endpoint must then extract the Fernet key from the byte stream and use the corresponding private key of public/private key pair to decrypt the Fernet key. The decrypted Fernet key can then be used to decrypt the remainder of the payload. The only known restriction on payload size is that the payload must fit into memory. """ @classmethod def decrypt(cls, encrypted_data: AnyStr, decryption_key_content: bytes) -> Optional[str]: """ Decrypts data encrypted by the `encrypt()` method of this class. The decryption algorithm is 1. Decode the base-64 representation of the JSON object 2. Load the JSON into a Python dictionary 3. Extract the encrypted Fernet key from the JSON object and decrypt it using our asymmetric decryption algorithm, i.e., the same algorithm we use to decrypt passwords. 4. Extract the encrypted data from the JSON object and decrypt it using the Fernet decryption algorithm. :param encrypted_data: The data to be decrypted :param decryption_key_content: The content of the OpenSSL private key file corresponding to the public cert used to encrypt the data :return: The decrypted data as a `str` object :raises: ValueError if the decryption key is missing from the `encrypted_data` payload :raises: ValueError if decryption_key_content` is None """ if encrypted_data is None: return None if decryption_key_content is None: raise ValueError("decryption_key_content can't be None") encrypted_data = _make_bytes(encrypted_data) # type: ignore json_object = json.loads(b64decode(encrypted_data).decode("utf-8")) encrypted_token_key = json_object.get("key") if encrypted_token_key is None: raise ValueError("token decryption key is missing from the payload") encrypted_token_key = _make_bytes(encrypted_token_key) # Machinations to make mypy happy decrypted_token_key = cast(str, SmallPayloadEncryptor.decrypt(encrypted_token_key, decryption_key_content)) decrypted_token_key = _make_bytes(decrypted_token_key) # type: ignore fernet_encryptor = Fernet(cast(bytes, decrypted_token_key)) return fernet_encryptor.decrypt(json_object["token"].encode("utf-8")).decode("utf-8") @classmethod def encrypt(cls, unencrypted_data: AnyStr, encryption_key_content: bytes) -> Optional[bytes]: """ Encrypts arbitrary data. This method uses a symmetric encryption algorithm (Fernet) to encrypt the data. This algorithm is capable of encrypting much larger payloads than asymmetric algorithms like RSA, which are limited by the key size and padding, if used. The encryption process is 1. Generate a random encryption key 2. Use that key to encrypt the original data. 3. Encrypt the key generated in step 1 by our asymmetric encryption algorithm, i.e., the same algorithm we use to encrypt passwords. This step may or may not use the same public/private keys we use for password encryption. 4. Create a Python dictionary with two entries: key: the encrypted Fernet key token: the data that was encrypted with the Fernet key Both the dictionary keys and values must be of type `str` to be JSON serializable. 5. Serialize the dictionary as a JSON string 6. Return a base-64 encoded representation of the JSON. :param unencrypted_data: The data to be encrypted :param encryption_key_content: The content of the OpenSSL X509 public certificate that will be used to encrypt the data :return: The encrypted key/text pair as a base-64 encoded `bytes` object :raises: ValueError if `encryption_key_content` is None """ if unencrypted_data is None: return None if encryption_key_content is None: raise ValueError("encryption_key_content can't be None") if isinstance(unencrypted_data, str): unencrypted_data = unencrypted_data.encode("utf-8") # type: ignore key = Fernet.generate_key() fernet_encryptor = Fernet(key) # Keys and values must be type `str`, not `bytes`, to be JSON serializable. result = { "key": SmallPayloadEncryptor.encrypt(key, encryption_key_content).decode("utf-8"), # type: ignore "token": fernet_encryptor.encrypt(cast(bytes, unencrypted_data)).decode("utf-8"), } return b64encode(json.dumps(result).encode("utf-8"))
| ver. 1.4 |
Github
|
.
| PHP 8.0.30 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка