diff options
author | S. Solomon Darnell | 2025-03-28 21:52:21 -0500 |
---|---|---|
committer | S. Solomon Darnell | 2025-03-28 21:52:21 -0500 |
commit | 4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch) | |
tree | ee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/pypdf/_crypt_providers | |
parent | cc961e04ba734dd72309fb548a2f97d67d578813 (diff) | |
download | gn-ai-master.tar.gz |
Diffstat (limited to '.venv/lib/python3.12/site-packages/pypdf/_crypt_providers')
5 files changed, 432 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py new file mode 100644 index 00000000..49d41128 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py @@ -0,0 +1,86 @@ +# Copyright (c) 2023, exiledkingcc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from pypdf._crypt_providers._base import CryptBase, CryptIdentity + +try: + from pypdf._crypt_providers._cryptography import ( + CryptAES, + CryptRC4, + aes_cbc_decrypt, + aes_cbc_encrypt, + aes_ecb_decrypt, + aes_ecb_encrypt, + crypt_provider, + rc4_decrypt, + rc4_encrypt, + ) + from pypdf._utils import Version + + if Version(crypt_provider[1]) <= Version("3.0"): + # This is due to the backend parameter being required back then: + # https://cryptography.io/en/latest/changelog/#v3-1 + raise ImportError("cryptography<=3.0 is not supported") # pragma: no cover +except ImportError: + try: + from pypdf._crypt_providers._pycryptodome import ( # type: ignore + CryptAES, + CryptRC4, + aes_cbc_decrypt, + aes_cbc_encrypt, + aes_ecb_decrypt, + aes_ecb_encrypt, + crypt_provider, + rc4_decrypt, + rc4_encrypt, + ) + except ImportError: + from pypdf._crypt_providers._fallback import ( # type: ignore + CryptAES, + CryptRC4, + aes_cbc_decrypt, + aes_cbc_encrypt, + aes_ecb_decrypt, + aes_ecb_encrypt, + crypt_provider, + rc4_decrypt, + rc4_encrypt, + ) + +__all__ = [ + "crypt_provider", + "CryptBase", + "CryptIdentity", + "CryptRC4", + "CryptAES", + "rc4_encrypt", + "rc4_decrypt", + "aes_ecb_encrypt", + "aes_ecb_decrypt", + "aes_cbc_encrypt", + "aes_cbc_decrypt", +] diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py new file mode 100644 index 00000000..894025f3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py @@ -0,0 +1,38 @@ +# Copyright (c) 2023, exiledkingcc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +class CryptBase: + def encrypt(self, data: bytes) -> bytes: # pragma: no cover + return data + + def decrypt(self, data: bytes) -> bytes: # pragma: no cover + return data + + +class CryptIdentity(CryptBase): + pass diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py new file mode 100644 index 00000000..f5537612 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py @@ -0,0 +1,118 @@ +# Copyright (c) 2023, exiledkingcc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import secrets + +from cryptography import __version__ +from cryptography.hazmat.primitives import padding +from cryptography.hazmat.primitives.ciphers.algorithms import AES + +try: + # 43.0.0 - https://cryptography.io/en/latest/changelog/#v43-0-0 + from cryptography.hazmat.decrepit.ciphers.algorithms import ARC4 +except ImportError: + from cryptography.hazmat.primitives.ciphers.algorithms import ARC4 +from cryptography.hazmat.primitives.ciphers.base import Cipher +from cryptography.hazmat.primitives.ciphers.modes import CBC, ECB + +from pypdf._crypt_providers._base import CryptBase + +crypt_provider = ("cryptography", __version__) + + +class CryptRC4(CryptBase): + def __init__(self, key: bytes) -> None: + self.cipher = Cipher(ARC4(key), mode=None) + + def encrypt(self, data: bytes) -> bytes: + encryptor = self.cipher.encryptor() + return encryptor.update(data) + encryptor.finalize() + + def decrypt(self, data: bytes) -> bytes: + decryptor = self.cipher.decryptor() + return decryptor.update(data) + decryptor.finalize() + + +class CryptAES(CryptBase): + def __init__(self, key: bytes) -> None: + self.alg = AES(key) + + def encrypt(self, data: bytes) -> bytes: + iv = secrets.token_bytes(16) + pad = padding.PKCS7(128).padder() + data = pad.update(data) + pad.finalize() + + cipher = Cipher(self.alg, CBC(iv)) + encryptor = cipher.encryptor() + return iv + encryptor.update(data) + encryptor.finalize() + + def decrypt(self, data: bytes) -> bytes: + iv = data[:16] + data = data[16:] + # for empty encrypted data + if not data: + return data + + # just for robustness, it does not happen under normal circumstances + if len(data) % 16 != 0: + pad = padding.PKCS7(128).padder() + data = pad.update(data) + pad.finalize() + + cipher = Cipher(self.alg, CBC(iv)) + decryptor = cipher.decryptor() + d = decryptor.update(data) + decryptor.finalize() + return d[: -d[-1]] + + +def rc4_encrypt(key: bytes, data: bytes) -> bytes: + encryptor = Cipher(ARC4(key), mode=None).encryptor() + return encryptor.update(data) + encryptor.finalize() + + +def rc4_decrypt(key: bytes, data: bytes) -> bytes: + decryptor = Cipher(ARC4(key), mode=None).decryptor() + return decryptor.update(data) + decryptor.finalize() + + +def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes: + encryptor = Cipher(AES(key), mode=ECB()).encryptor() + return encryptor.update(data) + encryptor.finalize() + + +def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes: + decryptor = Cipher(AES(key), mode=ECB()).decryptor() + return decryptor.update(data) + decryptor.finalize() + + +def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + encryptor = Cipher(AES(key), mode=CBC(iv)).encryptor() + return encryptor.update(data) + encryptor.finalize() + + +def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + decryptor = Cipher(AES(key), mode=CBC(iv)).decryptor() + return decryptor.update(data) + decryptor.finalize() diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py new file mode 100644 index 00000000..631fec19 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py @@ -0,0 +1,93 @@ +# Copyright (c) 2023, exiledkingcc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from pypdf._crypt_providers._base import CryptBase +from pypdf.errors import DependencyError + +_DEPENDENCY_ERROR_STR = "cryptography>=3.1 is required for AES algorithm" + + +crypt_provider = ("local_crypt_fallback", "0.0.0") + + +class CryptRC4(CryptBase): + def __init__(self, key: bytes) -> None: + self.s = bytearray(range(256)) + j = 0 + for i in range(256): + j = (j + self.s[i] + key[i % len(key)]) % 256 + self.s[i], self.s[j] = self.s[j], self.s[i] + + def encrypt(self, data: bytes) -> bytes: + s = bytearray(self.s) + out = [0 for _ in range(len(data))] + i, j = 0, 0 + for k in range(len(data)): + i = (i + 1) % 256 + j = (j + s[i]) % 256 + s[i], s[j] = s[j], s[i] + x = s[(s[i] + s[j]) % 256] + out[k] = data[k] ^ x + return bytes(bytearray(out)) + + def decrypt(self, data: bytes) -> bytes: + return self.encrypt(data) + + +class CryptAES(CryptBase): + def __init__(self, key: bytes) -> None: + pass + + def encrypt(self, data: bytes) -> bytes: + raise DependencyError(_DEPENDENCY_ERROR_STR) + + def decrypt(self, data: bytes) -> bytes: + raise DependencyError(_DEPENDENCY_ERROR_STR) + + +def rc4_encrypt(key: bytes, data: bytes) -> bytes: + return CryptRC4(key).encrypt(data) + + +def rc4_decrypt(key: bytes, data: bytes) -> bytes: + return CryptRC4(key).decrypt(data) + + +def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes: + raise DependencyError(_DEPENDENCY_ERROR_STR) + + +def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes: + raise DependencyError(_DEPENDENCY_ERROR_STR) + + +def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + raise DependencyError(_DEPENDENCY_ERROR_STR) + + +def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + raise DependencyError(_DEPENDENCY_ERROR_STR) diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py new file mode 100644 index 00000000..30a13e18 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py @@ -0,0 +1,97 @@ +# Copyright (c) 2023, exiledkingcc +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import secrets + +from Crypto import __version__ +from Crypto.Cipher import AES, ARC4 +from Crypto.Util.Padding import pad + +from pypdf._crypt_providers._base import CryptBase + +crypt_provider = ("pycryptodome", __version__) + + +class CryptRC4(CryptBase): + def __init__(self, key: bytes) -> None: + self.key = key + + def encrypt(self, data: bytes) -> bytes: + return ARC4.ARC4Cipher(self.key).encrypt(data) + + def decrypt(self, data: bytes) -> bytes: + return ARC4.ARC4Cipher(self.key).decrypt(data) + + +class CryptAES(CryptBase): + def __init__(self, key: bytes) -> None: + self.key = key + + def encrypt(self, data: bytes) -> bytes: + iv = secrets.token_bytes(16) + data = pad(data, 16) + aes = AES.new(self.key, AES.MODE_CBC, iv) + return iv + aes.encrypt(data) + + def decrypt(self, data: bytes) -> bytes: + iv = data[:16] + data = data[16:] + # for empty encrypted data + if not data: + return data + + # just for robustness, it does not happen under normal circumstances + if len(data) % 16 != 0: + data = pad(data, 16) + + aes = AES.new(self.key, AES.MODE_CBC, iv) + d = aes.decrypt(data) + return d[: -d[-1]] + + +def rc4_encrypt(key: bytes, data: bytes) -> bytes: + return ARC4.ARC4Cipher(key).encrypt(data) + + +def rc4_decrypt(key: bytes, data: bytes) -> bytes: + return ARC4.ARC4Cipher(key).decrypt(data) + + +def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes: + return AES.new(key, AES.MODE_ECB).encrypt(data) + + +def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes: + return AES.new(key, AES.MODE_ECB).decrypt(data) + + +def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + return AES.new(key, AES.MODE_CBC, iv).encrypt(data) + + +def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + return AES.new(key, AES.MODE_CBC, iv).decrypt(data) |