1# Copyright (c) 2023, exiledkingcc 
    2# All rights reserved. 
    3# 
    4# Redistribution and use in source and binary forms, with or without 
    5# modification, are permitted provided that the following conditions are 
    6# met: 
    7# 
    8# * Redistributions of source code must retain the above copyright notice, 
    9# this list of conditions and the following disclaimer. 
    10# * Redistributions in binary form must reproduce the above copyright notice, 
    11# this list of conditions and the following disclaimer in the documentation 
    12# and/or other materials provided with the distribution. 
    13# * The name of the author may not be used to endorse or promote products 
    14# derived from this software without specific prior written permission. 
    15# 
    16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    17# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    19# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
    20# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    21# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    22# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    23# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    24# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    25# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
    26# POSSIBILITY OF SUCH DAMAGE. 
    27 
    28import secrets 
    29 
    30from cryptography import __version__ 
    31from cryptography.hazmat.primitives import padding 
    32from cryptography.hazmat.primitives.ciphers.algorithms import AES 
    33 
    34try: 
    35    # 43.0.0 - https://cryptography.io/en/latest/changelog/#v43-0-0 
    36    from cryptography.hazmat.decrepit.ciphers.algorithms import ARC4 
    37except ImportError: 
    38    from cryptography.hazmat.primitives.ciphers.algorithms import ARC4 
    39from cryptography.hazmat.primitives.ciphers.base import Cipher 
    40from cryptography.hazmat.primitives.ciphers.modes import CBC, ECB 
    41 
    42from pypdf._crypt_providers._base import CryptBase 
    43 
    44crypt_provider = ("cryptography", __version__) 
    45 
    46 
    47class CryptRC4(CryptBase): 
    48    def __init__(self, key: bytes) -> None: 
    49        self.cipher = Cipher(ARC4(key), mode=None) 
    50 
    51    def encrypt(self, data: bytes) -> bytes: 
    52        encryptor = self.cipher.encryptor() 
    53        return encryptor.update(data) + encryptor.finalize() 
    54 
    55    def decrypt(self, data: bytes) -> bytes: 
    56        decryptor = self.cipher.decryptor() 
    57        return decryptor.update(data) + decryptor.finalize() 
    58 
    59 
    60class CryptAES(CryptBase): 
    61    def __init__(self, key: bytes) -> None: 
    62        self.alg = AES(key) 
    63 
    64    def encrypt(self, data: bytes) -> bytes: 
    65        iv = secrets.token_bytes(16) 
    66        pad = padding.PKCS7(128).padder() 
    67        data = pad.update(data) + pad.finalize() 
    68 
    69        cipher = Cipher(self.alg, CBC(iv)) 
    70        encryptor = cipher.encryptor() 
    71        return iv + encryptor.update(data) + encryptor.finalize() 
    72 
    73    def decrypt(self, data: bytes) -> bytes: 
    74        iv = data[:16] 
    75        data = data[16:] 
    76        # for empty encrypted data 
    77        if not data: 
    78            return data 
    79 
    80        # just for robustness, it does not happen under normal circumstances 
    81        if len(data) % 16 != 0: 
    82            pad = padding.PKCS7(128).padder() 
    83            data = pad.update(data) + pad.finalize() 
    84 
    85        cipher = Cipher(self.alg, CBC(iv)) 
    86        decryptor = cipher.decryptor() 
    87        d = decryptor.update(data) + decryptor.finalize() 
    88        return d[: -d[-1]] 
    89 
    90 
    91def rc4_encrypt(key: bytes, data: bytes) -> bytes: 
    92    encryptor = Cipher(ARC4(key), mode=None).encryptor() 
    93    return encryptor.update(data) + encryptor.finalize() 
    94 
    95 
    96def rc4_decrypt(key: bytes, data: bytes) -> bytes: 
    97    decryptor = Cipher(ARC4(key), mode=None).decryptor() 
    98    return decryptor.update(data) + decryptor.finalize() 
    99 
    100 
    101def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes: 
    102    encryptor = Cipher(AES(key), mode=ECB()).encryptor() 
    103    return encryptor.update(data) + encryptor.finalize() 
    104 
    105 
    106def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes: 
    107    decryptor = Cipher(AES(key), mode=ECB()).decryptor() 
    108    return decryptor.update(data) + decryptor.finalize() 
    109 
    110 
    111def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: 
    112    encryptor = Cipher(AES(key), mode=CBC(iv)).encryptor() 
    113    return encryptor.update(data) + encryptor.finalize() 
    114 
    115 
    116def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: 
    117    decryptor = Cipher(AES(key), mode=CBC(iv)).decryptor() 
    118    return decryptor.update(data) + decryptor.finalize()