From 721b5b627ccee847a4bd8057eb50cc8cf4bae42e Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Tue, 12 Apr 2022 12:29:58 +0800 Subject: [PATCH 01/13] decrypt support V4 and AES-128 NOTICE: 1. Python3 only 2. need PyCryptodome for AES --- PyPDF2/encryption.py | 478 ++++++++++++++++++++++++++++++++++ PyPDF2/pdf.py | 80 ++---- Resources/encryption/enc0.pdf | Bin 0 -> 15049 bytes Resources/encryption/enc1.pdf | Bin 0 -> 15445 bytes Resources/encryption/enc2.pdf | Bin 0 -> 15451 bytes Resources/encryption/enc3.pdf | Bin 0 -> 15450 bytes Resources/encryption/enc4.pdf | Bin 0 -> 15451 bytes Resources/encryption/enc5.pdf | Bin 0 -> 15540 bytes Resources/encryption/enc6.pdf | Bin 0 -> 16395 bytes Resources/encryption/enc7.pdf | Bin 0 -> 16709 bytes Resources/encryption/enc8.pdf | Bin 0 -> 16709 bytes Resources/encryption/enc9.pdf | Bin 0 -> 16709 bytes Tests/test_encryption.py | 48 ++++ 13 files changed, 545 insertions(+), 61 deletions(-) create mode 100644 PyPDF2/encryption.py create mode 100644 Resources/encryption/enc0.pdf create mode 100644 Resources/encryption/enc1.pdf create mode 100644 Resources/encryption/enc2.pdf create mode 100644 Resources/encryption/enc3.pdf create mode 100644 Resources/encryption/enc4.pdf create mode 100644 Resources/encryption/enc5.pdf create mode 100644 Resources/encryption/enc6.pdf create mode 100644 Resources/encryption/enc7.pdf create mode 100644 Resources/encryption/enc8.pdf create mode 100644 Resources/encryption/enc9.pdf create mode 100644 Tests/test_encryption.py diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py new file mode 100644 index 000000000..76af876a9 --- /dev/null +++ b/PyPDF2/encryption.py @@ -0,0 +1,478 @@ +# coding: utf-8 +# +# Copyright (c) 2022, 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 hashlib +import random +import struct +import typing + +from PyPDF2.generic import * + + +class CryptBase: + def encrypt(self, data: bytes) -> bytes: return data + def decrypt(self, data: bytes) -> bytes: return data + +try: + from Crypto.Cipher import ARC4, AES + + 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 = bytes(bytearray(random.randint(0, 255) for _ in range(16))) + p = 16 - len(data) % 16 + text = text + bytes(bytearray(p for _ in range(p))) + aes = AES.new(self.key, AES.MODE_CBC, iv) + return aes.encrypt(data) + + def decrypt(self, data: bytes) -> bytes: + iv = data[:16] + data = data[16:] + aes = AES.new(self.key, AES.MODE_CBC, iv) + d = aes.decrypt(data) + return d[:-d[-1]] + +except ImportError: + + class CryptRC4(CryptBase): + def __init__(self, key: bytes) -> None: + self.S = list(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 = [x for x in self.S] + out = list(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] + out[k] = S[( S[i] + S[j]) % 256] + return bytes(bytearray(out)) + + def decrypt(self, data: bytes) -> bytes: + return self.encrypt(data) + + class CryptAES(CryptBase): + def __init__(self, key: bytes) -> None: + self.key = key + + def encrypt(self, data: bytes) -> bytes: + raise RuntimeError("PyCryptodome is required for AES encryption") + + def decrypt(self, data: bytes) -> bytes: + raise RuntimeError("PyCryptodome is required for AES decryption") + + +class CryptIdentity(CryptBase): + pass + + +_PADDING = bytes([ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, + 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, + 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A +]) + +def _padding(data: bytes) -> bytes: + return (data + _PADDING)[:32] + +def _bytes(text: str) -> bytes: + try: + return text.encode('latin-1') + except Exception: # noqa + return text.encode('utf-8') + + +class StandardSecurityHandler: + def __init__(self, rev: int, perm: int, keylen: int, metadata_encrypted: bool, first_id_entry: bytes) -> None: + self.R = rev + self.P = (perm + 0x100000000) % 0x100000000 # maybe < 0 + self.Length = keylen + self.metadata_encrypted = metadata_encrypted + self.id1_entry = first_id_entry if first_id_entry is not None else b"" + + self.key: typing.Optional[bytes] = None + + def generate(self, user_pwd: str, owner_pwd: str=None) -> typing.Tuple[bytes, bytes]: + u_entry = self._compute_U_value(user_pwd, owner_pwd) + o_entry = self._compute_O_value(user_pwd, owner_pwd) + return u_entry, o_entry + + def auth(self, u_entry: bytes, o_entry: bytes, user_pwd: str, owner_pwd: str=None) -> int: + if self._auth_user_password(u_entry, o_entry, user_pwd): + return 1 + elif self._auth_owner_password(u_entry, o_entry, owner_pwd): + return 2 + else: + self.key = None + return 0 + + def _compute_key(self, password: bytes, o_entry: bytes) -> bytes: + """ + Algorithm 2: Computing an encryption key + """ + + """ a) Pad or truncate the password string to exactly 32 bytes. If the password string is more than 32 bytes long, + use only its first 32 bytes; if it is less than 32 bytes long, pad it by appending the required number of + additional bytes from the beginning of the following padding string: + < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 + 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A > + That is, if the password string is n bytes long, append the first 32 - n bytes of the padding string to the end + of the password string. If the password string is empty (zero-length), meaning there is no user password, + substitute the entire padding string in its place. + """ + a = _padding(password) + """ b) Initialize the MD5 hash function and pass the result of step (a) as input to this function. """ + u_hash = hashlib.md5(a) + """ c) Pass the value of the encryption dictionary’s O entry to the MD5 hash function. ("Algorithm 3: Computing + the encryption dictionary’s O (owner password) value" shows how the O value is computed.) + """ + u_hash.update(o_entry) + """ d) Convert the integer value of the P entry to a 32-bit unsigned binary number and pass these bytes to the + MD5 hash function, low-order byte first. + """ + u_hash.update(struct.pack('= 3 and not self.metadata_encrypted: + u_hash.update(b"\xff\xff\xff\xff") + """ g) Finish the hash. """ + u_hash_digest = u_hash.digest() + """ h) (Security handlers of revision 3 or greater) Do the following 50 times: Take the output from the previous + MD5 hash and pass the first n bytes of the output as input into a new MD5 hash, where n is the number of + bytes of the encryption key as defined by the value of the encryption dictionary’s Length entry. + """ + length = self.Length // 8 + if self.R >= 3: + for _ in range(50): + u_hash_digest = hashlib.md5(u_hash_digest[:length]).digest() + """ i) Set the encryption key to the first n bytes of the output from the final MD5 hash, where n shall always be 5 + for security handlers of revision 2 but, for security handlers of revision 3 or greater, shall depend on the + value of the encryption dictionary’s Length entry. + """ + return u_hash_digest[:length] + + def _compute_O_value(self, user_pwd: bytes, owner_pwd: bytes=None) -> bytes: + """ + Algorithm 3: Computing the encryption dictionary’s O (owner password) value + """ + + """ a) Pad or truncate the owner password string as described in step (a) of "Algorithm 2: Computing an + encryption key". If there is no owner password, use the user password instead. + """ + a = _padding(owner_pwd if owner_pwd else user_pwd) + """ b) Initialize the MD5 hash function and pass the result of step (a) as input to this function. """ + o_hash_digest = hashlib.md5(a).digest() + """ c) (Security handlers of revision 3 or greater) Do the following 50 times: Take the output from the previous + MD5 hash and pass it as input into a new MD5 hash. """ + if self.R >= 3: + for _ in range(50): + o_hash_digest = hashlib.md5(o_hash_digest).digest() + """ d) Create an RC4 encryption key using the first n bytes of the output from the final MD5 hash, where n shall + always be 5 for security handlers of revision 2 but, for security handlers of revision 3 or greater, shall + depend on the value of the encryption dictionary’s Length entry. + """ + rc4_key = o_hash_digest[:self.Length // 8] + """ e) Pad or truncate the user password string as described in step (a) of "Algorithm 2: Computing an encryption key". """ + a = _padding(user_pwd) + """ f) Encrypt the result of step (e), using an RC4 encryption function with the encryption key obtained in step (d). """ + rc4_enc = CryptRC4(rc4_key).encrypt(a) + """ g) (Security handlers of revision 3 or greater) Do the following 19 times: Take the output from the previous + invocation of the RC4 function and pass it as input to a new invocation of the function; use an encryption + key generated by taking each byte of the encryption key obtained in step (d) and performing an XOR + (exclusive or) operation between that byte and the single-byte value of the iteration counter (from 1 to 19). + """ + if self.R >= 3: + for i in range(1, 20): + key = bytes(bytearray([x ^ i for x in rc4_key])) + rc4_enc = CryptRC4(key).encrypt(rc4_enc) + """ h) Store the output from the final invocation of the RC4 function as the value of the O entry in the encryption dictionary. """ + return rc4_enc + + def _compute_U_value(self, user_pwd: bytes, o_entry: bytes) -> bytes: + """ + Algorithm 4: Computing the encryption dictionary’s U (user password) value (Security handlers of revision 2) + """ + """ a) Create an encryption key based on the user password string, as described in "Algorithm 2: Computing an encryption key". """ + self.key = self._compute_key(user_pwd, o_entry) + """ b) Encrypt the 32-byte padding string shown in step (a) of "Algorithm 2: Computing an encryption key", using + an RC4 encryption function with the encryption key from the preceding step. + c) Store the result of step (b) as the value of the U entry in the encryption dictionary. + """ + if self.R <= 2: + value = CryptRC4(self.key).encrypt(_PADDING) + return value + + """ + Algorithm 5: Computing the encryption dictionary’s U (user password) value (Security handlers of revision 3 or greater) + """ + """ a) Create an encryption key based on the user password string, as described in "Algorithm 2: Computing an encryption key". """ + """ b) Initialize the MD5 hash function and pass the 32-byte padding string shown in step (a) of "Algorithm 2: + Computing an encryption key" as input to this function. """ + u_hash = hashlib.md5(_PADDING) + """ c) Pass the first element of the file’s file identifier array (the value of the ID entry in the document’s trailer + dictionary; see Table 15) to the hash function and finish the hash. """ + u_hash.update(self.id1_entry) + """ d) Encrypt the 16-byte result of the hash, using an RC4 encryption function with the encryption key from step (a). """ + rc4_enc = CryptRC4(self.key).encrypt(u_hash.digest()) + """ e) Do the following 19 times: Take the output from the previous invocation of the RC4 function and pass it as + input to a new invocation of the function; use an encryption key generated by taking each byte of the + original encryption key obtained in step (a) and performing an XOR (exclusive or) operation between that + byte and the single-byte value of the iteration counter (from 1 to 19). + """ + for i in range(1, 20): + key = bytes(bytearray([x ^ i for x in self.key])) + rc4_enc = CryptRC4(key).encrypt(rc4_enc) + """ f) Append 16 bytes of arbitrary padding to the output from the final invocation of the RC4 function and store + the 32-byte result as the value of the U entry in the encryption dictionary. + """ + return _padding(rc4_enc) + + def _auth_user_password(self, u_entry: bytes, o_entry: bytes, user_pwd: bytes) -> bool: + """ + Algorithm 6: Authenticating the user password + + a) Perform all but the last step of "Algorithm 4: Computing the encryption dictionary’s U (user password) + value (Security handlers of revision 2)" or "Algorithm 5: Computing the encryption dictionary’s U (user + password) value (Security handlers of revision 3 or greater)" using the supplied password string. + b) If the result of step (a) is equal to the value of the encryption dictionary’s U entry (comparing on the first 16 + bytes in the case of security handlers of revision 3 or greater), the password supplied is the correct user + password. The key obtained in step (a) (that is, in the first step of "Algorithm 4: Computing the encryption + dictionary’s U (user password) value (Security handlers of revision 2)" or "Algorithm 5: Computing the + encryption dictionary’s U (user password) value (Security handlers of revision 3 or greater)") shall be used + to decrypt the document. + """ + u_value = self._compute_U_value(user_pwd, o_entry) + if self.R >= 3: + u_value = u_value[:16] + u_entry = u_entry[:16] + return u_value == u_entry + + def _auth_owner_password(self, u_entry: bytes, o_entry: bytes, owner_pwd: bytes=None) -> bool: + """ + Algorithm 7: Authenticating the owner password + + a) Compute an encryption key from the supplied password string, as described in steps (a) to (d) of + "Algorithm 3: Computing the encryption dictionary’s O (owner password) value". + b) (Security handlers of revision 2 only) Decrypt the value of the encryption dictionary’s O entry, using an RC4 + encryption function with the encryption key computed in step (a). + (Security handlers of revision 3 or greater) Do the following 20 times: Decrypt the value of the encryption + dictionary’s O entry (first iteration) or the output from the previous iteration (all subsequent iterations), + using an RC4 encryption function with a different encryption key at each iteration. The key shall be + generated by taking the original key (obtained in step (a)) and performing an XOR (exclusive or) operation + between each byte of the key and the single-byte value of the iteration counter (from 19 to 0). + c) The result of step (b) purports to be the user password. Authenticate this user password using "Algorithm 6: + Authenticating the user password". If it is correct, the password supplied is the correct owner password. + """ + if owner_pwd is None: + owner_pwd = b"" + a = _padding(owner_pwd) + o_hash_digest = hashlib.md5(a).digest() + if self.R >= 3: + for _ in range(50): + o_hash_digest = hashlib.md5(o_hash_digest).digest() + rc4_key = o_hash_digest[:self.Length // 8] + + if self.R <= 2: + u_pwd = CryptRC4(rc4_key).decrypt(o_entry) + else: + u_pwd = o_entry + for i in range(19, -1, -1): + key = bytes(bytearray([x ^ i for x in rc4_key])) + u_pwd = CryptRC4(key).decrypt(u_pwd) + return self._auth_user_password(u_entry, o_entry, u_pwd) + + +class CryptFilter: + def __init__(self, stmCrypt: CryptBase, strCrypt: CryptBase, efCrypt: CryptBase) -> None: + self.stmCrypt = stmCrypt + self.strCrypt = strCrypt + self.efCrypt = efCrypt + + def encryptObject(self, obj: PdfObject) -> PdfObject: + # TODO + raise NotImplementedError + + def decryptObject(self, obj: PdfObject) -> PdfObject: + if isinstance(obj, ByteStringObject) or isinstance(obj, TextStringObject): + data = self.strCrypt.decrypt(obj.original_bytes) + obj = createStringObject(data) + elif isinstance(obj, StreamObject): + obj._data = self.stmCrypt.decrypt(obj._data) + elif isinstance(obj, DictionaryObject): + for dictkey, value in list(obj.items()): + obj[dictkey] = self.decryptObject(value) + elif isinstance(obj, ArrayObject): + for i in range(len(obj)): + obj[i] = self.decryptObject(obj[i]) + return obj + + +class Encryption: + def __init__(self, algV: int, rev: int, perm: int, keylen: int, + metadata_encrypted: bool, first_id_entry: bytes, + StmF: str, StrF: str, EFF: str) -> None: + self.algV = algV + self.handler = StandardSecurityHandler(rev, perm, keylen, metadata_encrypted, first_id_entry) + self.StmF = StmF + self.StrF = StrF + self.EFF = EFF + + def key(self) -> typing.Optional[bytes]: + return self.handler.key + + def encryptObject(self, obj: PdfObject) -> PdfObject: + # TODO + raise NotImplemented + + def decryptObject(self, obj: PdfObject, idnum: int, generation: int) -> PdfObject: + """ + Algorithm 1: Encryption of data using the RC4 or AES algorithms + + a) Obtain the object number and generation number from the object identifier of the string or stream to be + encrypted (see 7.3.10, "Indirect Objects"). If the string is a direct object, use the identifier of the indirect + object containing it. + b) For all strings and streams without crypt filter specifier; treating the object number and generation number + as binary integers, extend the original n-byte encryption key to n + 5 bytes by appending the low-order 3 + bytes of the object number and the low-order 2 bytes of the generation number in that order, low-order byte + first. (n is 5 unless the value of V in the encryption dictionary is greater than 1, in which case n is the value + of Length divided by 8.) + If using the AES algorithm, extend the encryption key an additional 4 bytes by adding the value “sAlT”, + which corresponds to the hexadecimal values 0x73, 0x41, 0x6C, 0x54. (This addition is done for backward + compatibility and is not intended to provide additional security.) + c) Initialize the MD5 hash function and pass the result of step (b) as input to this function. + d) Use the first (n + 5) bytes, up to a maximum of 16, of the output from the MD5 hash as the key for the RC4 + or AES symmetric key algorithms, along with the string or stream data to be encrypted. + If using the AES algorithm, the Cipher Block Chaining (CBC) mode, which requires an initialization vector, + is used. The block size parameter is set to 16 bytes, and the initialization vector is a 16-byte random + number that is stored as the first 16 bytes of the encrypted stream or string. + """ + pack1 = struct.pack(" CryptBase: + if method == "/AESV2": + return CryptAES(aes_key) + elif method == "/Identity": + return CryptIdentity() + else: + return CryptRC4(rc4_key) + + def encryptPdf(self, user_pwd: str, owner_pwd: str=None) -> DictionaryObject: + # TODO + raise NotImplemented + + def decryptPdf(self, u_entry: bytes, o_entry: bytes, user_pwd: str, owner_pwd: str=None) -> int: + user_pwd = _bytes(user_pwd) + if owner_pwd is not None: + owner_pwd = _bytes(owner_pwd) + return self.handler.auth(u_entry, o_entry, user_pwd, owner_pwd) + + @staticmethod + def read(encryption_entry: DictionaryObject, first_id_entry: bytes=None) -> "Encryption": + filter = encryption_entry.get("/Filter") + if filter != "/Standard": + raise NotImplementedError("only Standard PDF encryption handler is available") + if "/SubFilter" in encryption_entry: + raise NotImplementedError("/SubFilter NOT supported") + + StmF = "/V2" + StrF = "/V2" + EFF = "/V2" + + V = encryption_entry.get("/V", 0) + if V not in (1, 2, 3, 4): + raise NotImplementedError("Encryption V=%d NOT supported" % V) + if V == 4: + filters = encryption_entry["/CF"] + + StmF = encryption_entry.get("/StmF", "/Identity") + StrF = encryption_entry.get("/StrF", "/Identity") + EFF = encryption_entry.get("/EFF", StmF) + + if StmF != "/Identity": + StmF = filters[StmF]["/CFM"] + if StrF != "/Identity": + StrF = filters[StrF]["/CFM"] + if EFF != "/Identity": + EFF = filters[EFF]["/CFM"] + + allowed_methods = ("/Identity", "/V2", "/AESV2") + if StmF not in allowed_methods: + raise NotImplementedError("StmF Method %s NOT supported!" % StmF) + if StrF not in allowed_methods: + raise NotImplementedError("StrF Method %s NOT supported!" % StrF) + if EFF not in allowed_methods: + raise NotImplementedError("EFF Method %s NOT supported!" % EFF) + + R = encryption_entry["/R"] + P = encryption_entry["/P"] + Length = encryption_entry.get("/Length", 5 * 8) + metadata_encrypted = encryption_entry.get("/EncryptMetadata", True) + return Encryption(V, R, P, Length, metadata_encrypted, first_id_entry, StmF, StrF, EFF) diff --git a/PyPDF2/pdf.py b/PyPDF2/pdf.py index a762ac69f..58faabbfe 100644 --- a/PyPDF2/pdf.py +++ b/PyPDF2/pdf.py @@ -1692,18 +1692,10 @@ def getObject(self, indirectReference): # override encryption is used for the /Encrypt dictionary if not self._override_encryption and self.isEncrypted: - # if we don't have the encryption key: - if not hasattr(self, '_decryption_key'): + if not hasattr(self, "_encryption"): raise utils.PdfReadError("file has not been decrypted") - # otherwise, decrypt here... - import struct - pack1 = struct.pack("= 3: - U, key = _alg35(password, rev, - encrypt[SA.LENGTH].getObject() // 8, owner_entry, - p_entry, id1_entry, - encrypt.get("/EncryptMetadata", BooleanObject(False)).getObject()) - U, real_U = U[:16], real_U[:16] - return U == real_U, key + # already got the KEY + if hasattr(self, "_encryption"): + return 3 + from PyPDF2.encryption import Encryption + id_entry = self.trailer.get("/ID") + id1_entry = id_entry[0].getObject().original_bytes if id_entry else None + encryptEntry = self.trailer['/Encrypt'].getObject() + encryption = Encryption.read(encryptEntry, id1_entry) + u_entry = encryptEntry["/U"].getObject().original_bytes + o_entry = encryptEntry["/O"].getObject().original_bytes + # maybe password is owner password + # TODO: add/modify api to set owner password + rr = encryption.decryptPdf(u_entry, o_entry, password, "") + if rr > 0: + self._encryption = encryption + return rr def getIsEncrypted(self): return "/Encrypt" in self.trailer diff --git a/Resources/encryption/enc0.pdf b/Resources/encryption/enc0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0d218c890e76af93a705995b8afad9cb05c5b327 GIT binary patch literal 15049 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 literal 0 HcmV?d00001 diff --git a/Resources/encryption/enc4.pdf b/Resources/encryption/enc4.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d6faecbb696683868759683f9d9a9a2560d225b3 GIT binary patch literal 15451 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 B_oDy+ literal 0 HcmV?d00001 diff --git a/Resources/encryption/enc5.pdf b/Resources/encryption/enc5.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a6a2f2f8ba599a93d3e82023ef65752b1ff99dd9 GIT binary patch literal 15540 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 literal 0 HcmV?d00001 diff --git a/Resources/encryption/enc7.pdf b/Resources/encryption/enc7.pdf new file mode 100644 index 0000000000000000000000000000000000000000..406b6ed8508224fc6347a21d75a77f50177b5ea3 GIT binary patch literal 16709 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 J>0YP*e*lx9Dz5+l literal 0 HcmV?d00001 diff --git a/Resources/encryption/enc8.pdf b/Resources/encryption/enc8.pdf new file mode 100644 index 0000000000000000000000000000000000000000..83ab2aa4561cf999b312eb83d04e39edc0a15f55 GIT binary patch literal 16709 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 IuTJxS0ABw#zyJUM literal 0 HcmV?d00001 diff --git a/Resources/encryption/enc9.pdf b/Resources/encryption/enc9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3b5bde23dc4ceac77ea95301fb6bcb7cfa8067e9 GIT binary patch literal 16709 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 F{2xD~7M=hA literal 0 HcmV?d00001 diff --git a/Tests/test_encryption.py b/Tests/test_encryption.py new file mode 100644 index 000000000..8f9371186 --- /dev/null +++ b/Tests/test_encryption.py @@ -0,0 +1,48 @@ +import os +import pytest +import PyPDF2 + +TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) +PROJECT_ROOT = os.path.dirname(TESTS_ROOT) +RESOURCE_ROOT = os.path.join(PROJECT_ROOT, "Resources") + + +@pytest.mark.parametrize( + "src", + [ + # unencrypted pdf + (os.path.join(RESOURCE_ROOT, "encryption", "enc0.pdf")), + + # created by `qpdf --encrypt "" "" 40 -- enc0.pdf enc1.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc1.pdf")), + # created by `qpdf --encrypt "" "" 128 -- enc0.pdf enc2.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc2.pdf")), + # created by `qpdf --encrypt "asdfzxcv" "" 40 -- enc0.pdf enc3.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc3.pdf")), + # created by `qpdf --encrypt "asdfzxcv" "" 128 -- enc0.pdf enc4.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc4.pdf")), + + # V=4 and AES128 + # created by `qpdf --encrypt "asdfzxcv" "" 128 --force-V4 -- enc0.pdf enc5.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc5.pdf")), + # created by `qpdf --encrypt "asdfzxcv" "" 128 --use-aes=y -- enc0.pdf enc6.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc6.pdf")), + + # # V=5 and AES256 (TODO) + # # created by `qpdf --encrypt "" "" 256 -- enc0.pdf enc6.pdf` + # (os.path.join(RESOURCE_ROOT, "encryption", "enc7.pdf")), + # # created by `qpdf --encrypt "asdfzxcv" "" 256 -- enc0.pdf enc6.pdf` + # (os.path.join(RESOURCE_ROOT, "encryption", "enc8.pdf")), + # # created by `qpdf --encrypt "" "asdfzxcv" 256 -- enc0.pdf enc6.pdf` + # (os.path.join(RESOURCE_ROOT, "encryption", "enc9.pdf")), + ], +) +def test_encryption(src): + with open(src, "rb") as inputfile: + ipdf = PyPDF2.PdfFileReader(inputfile) + if src.endswith("enc0.pdf"): + assert ipdf.isEncrypted == False + else: + assert ipdf.isEncrypted == True + ipdf.decrypt("asdfzxcv") + assert ipdf.getNumPages() == 1 From 2f8e33ab6929e9acb03c2e44af9efbb1479b804e Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Fri, 15 Apr 2022 10:52:40 +0800 Subject: [PATCH 02/13] fix and update test --- PyPDF2/encryption.py | 23 ++++++++++++----------- Tests/test_encryption.py | 12 ++++++++++++ tox.ini | 1 + 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index 76af876a9..889e76006 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -59,9 +59,9 @@ def __init__(self, key: bytes) -> None: def encrypt(self, data: bytes) -> bytes: iv = bytes(bytearray(random.randint(0, 255) for _ in range(16))) p = 16 - len(data) % 16 - text = text + bytes(bytearray(p for _ in range(p))) + data += bytes(bytearray(p for _ in range(p))) aes = AES.new(self.key, AES.MODE_CBC, iv) - return aes.encrypt(data) + return iv + aes.encrypt(data) def decrypt(self, data: bytes) -> bytes: iv = data[:16] @@ -77,18 +77,19 @@ def __init__(self, key: bytes) -> None: self.S = list(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] + 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 = [x for x in self.S] out = list(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] - out[k] = S[( S[i] + S[j]) % 256] + 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: @@ -339,7 +340,7 @@ def __init__(self, stmCrypt: CryptBase, strCrypt: CryptBase, efCrypt: CryptBase) def encryptObject(self, obj: PdfObject) -> PdfObject: # TODO - raise NotImplementedError + return NotImplemented def decryptObject(self, obj: PdfObject) -> PdfObject: if isinstance(obj, ByteStringObject) or isinstance(obj, TextStringObject): @@ -371,7 +372,7 @@ def key(self) -> typing.Optional[bytes]: def encryptObject(self, obj: PdfObject) -> PdfObject: # TODO - raise NotImplemented + return NotImplemented def decryptObject(self, obj: PdfObject, idnum: int, generation: int) -> PdfObject: """ @@ -426,7 +427,7 @@ def _getCrypt(method: str, rc4_key: bytes, aes_key: bytes) -> CryptBase: def encryptPdf(self, user_pwd: str, owner_pwd: str=None) -> DictionaryObject: # TODO - raise NotImplemented + return NotImplemented def decryptPdf(self, u_entry: bytes, o_entry: bytes, user_pwd: str, owner_pwd: str=None) -> int: user_pwd = _bytes(user_pwd) diff --git a/Tests/test_encryption.py b/Tests/test_encryption.py index 8f9371186..69ac66996 100644 --- a/Tests/test_encryption.py +++ b/Tests/test_encryption.py @@ -46,3 +46,15 @@ def test_encryption(src): assert ipdf.isEncrypted == True ipdf.decrypt("asdfzxcv") assert ipdf.getNumPages() == 1 + metadict = ipdf.getDocumentInfo() + dd = dict(metadict) + # remove empty value entry + dd = {x[0]: x[1] for x in dd.items() if x[1]} + assert dd == { + '/Author': 'cheng', + '/CreationDate': "D:20220414132421+05'24'", + '/Creator': 'WPS Writer', + '/ModDate': "D:20220414132421+05'24'", + '/SourceModified': "D:20220414132421+05'24'", + '/Trapped': '/False' + } diff --git a/tox.ini b/tox.ini index 517e48eba..41fd77955 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,7 @@ envlist = [testenv] deps = + PyCryptodome pillow pytest pytest-cov From 26af6ea740b8fd35d8bbdc8dfe611f60fcd0bbda Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Fri, 15 Apr 2022 18:20:57 +0800 Subject: [PATCH 03/13] add pure python AES --- PyPDF2/_aes.py | 821 +++++++++++++++++++++++++++++++++++++++++++ PyPDF2/encryption.py | 14 +- tox.ini | 1 - 3 files changed, 832 insertions(+), 4 deletions(-) create mode 100644 PyPDF2/_aes.py diff --git a/PyPDF2/_aes.py b/PyPDF2/_aes.py new file mode 100644 index 000000000..7eb486e1c --- /dev/null +++ b/PyPDF2/_aes.py @@ -0,0 +1,821 @@ +# coding: utf-8 +# +# Copyright (c) 2022, 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. + +""" +based on rijndael-alg-fst.c +""" + +import struct +import typing + + +_TE0 = ( + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, + 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, + 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, + 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, + 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, + 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, + 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, + 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, + 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, + 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, + 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, + 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, + 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, + 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, + 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, +) +_TE1 = ( + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, +) +_TE2 = ( + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, +) +_TE3 = ( + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, +) +_TE4 = ( + 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, + 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, + 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, + 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, + 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, + 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515, + 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, + 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, + 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, + 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, + 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, + 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, + 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, + 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8, + 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, + 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, + 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, + 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, + 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, + 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, + 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, + 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979, + 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, + 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, + 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, + 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, + 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, + 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, + 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, + 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf, + 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, + 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616, +) +_TD0 = ( + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, + 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, + 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, + 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, + 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, + 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, + 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, + 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, + 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, + 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, + 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, + 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, + 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, + 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, + 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, +) +_TD1 = ( + 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, + 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, + 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, + 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, + 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, + 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, + 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, + 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, + 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, + 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, + 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, + 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, + 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, + 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, + 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, + 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, + 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, + 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, + 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, + 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, + 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, + 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, + 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, + 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, + 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, + 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, + 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, + 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, + 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, + 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, + 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, + 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, +) +_TD2 = ( + 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, + 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, + 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, + 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, + 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, + 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, + 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, + 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, + 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, + 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, + 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, + 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, + 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, + 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, + 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, + 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, + 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, + 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, + 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, + 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, + 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, + 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, + 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, + 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, + 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, + 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, + 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, + 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, + 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, + 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, + 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, + 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, +) +_TD3 = ( + 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, + 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, + 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, + 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, + 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, + 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, + 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, + 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, + 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, + 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, + 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, + 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, + 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, + 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, + 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, + 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, + 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, + 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, + 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, + 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, + 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, + 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, + 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, + 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, + 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, + 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, + 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, + 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, + 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, + 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, + 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, + 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, +) +_TD4 = ( + 0x52525252, 0x09090909, 0x6a6a6a6a, 0xd5d5d5d5, 0x30303030, 0x36363636, 0xa5a5a5a5, 0x38383838, + 0xbfbfbfbf, 0x40404040, 0xa3a3a3a3, 0x9e9e9e9e, 0x81818181, 0xf3f3f3f3, 0xd7d7d7d7, 0xfbfbfbfb, + 0x7c7c7c7c, 0xe3e3e3e3, 0x39393939, 0x82828282, 0x9b9b9b9b, 0x2f2f2f2f, 0xffffffff, 0x87878787, + 0x34343434, 0x8e8e8e8e, 0x43434343, 0x44444444, 0xc4c4c4c4, 0xdededede, 0xe9e9e9e9, 0xcbcbcbcb, + 0x54545454, 0x7b7b7b7b, 0x94949494, 0x32323232, 0xa6a6a6a6, 0xc2c2c2c2, 0x23232323, 0x3d3d3d3d, + 0xeeeeeeee, 0x4c4c4c4c, 0x95959595, 0x0b0b0b0b, 0x42424242, 0xfafafafa, 0xc3c3c3c3, 0x4e4e4e4e, + 0x08080808, 0x2e2e2e2e, 0xa1a1a1a1, 0x66666666, 0x28282828, 0xd9d9d9d9, 0x24242424, 0xb2b2b2b2, + 0x76767676, 0x5b5b5b5b, 0xa2a2a2a2, 0x49494949, 0x6d6d6d6d, 0x8b8b8b8b, 0xd1d1d1d1, 0x25252525, + 0x72727272, 0xf8f8f8f8, 0xf6f6f6f6, 0x64646464, 0x86868686, 0x68686868, 0x98989898, 0x16161616, + 0xd4d4d4d4, 0xa4a4a4a4, 0x5c5c5c5c, 0xcccccccc, 0x5d5d5d5d, 0x65656565, 0xb6b6b6b6, 0x92929292, + 0x6c6c6c6c, 0x70707070, 0x48484848, 0x50505050, 0xfdfdfdfd, 0xedededed, 0xb9b9b9b9, 0xdadadada, + 0x5e5e5e5e, 0x15151515, 0x46464646, 0x57575757, 0xa7a7a7a7, 0x8d8d8d8d, 0x9d9d9d9d, 0x84848484, + 0x90909090, 0xd8d8d8d8, 0xabababab, 0x00000000, 0x8c8c8c8c, 0xbcbcbcbc, 0xd3d3d3d3, 0x0a0a0a0a, + 0xf7f7f7f7, 0xe4e4e4e4, 0x58585858, 0x05050505, 0xb8b8b8b8, 0xb3b3b3b3, 0x45454545, 0x06060606, + 0xd0d0d0d0, 0x2c2c2c2c, 0x1e1e1e1e, 0x8f8f8f8f, 0xcacacaca, 0x3f3f3f3f, 0x0f0f0f0f, 0x02020202, + 0xc1c1c1c1, 0xafafafaf, 0xbdbdbdbd, 0x03030303, 0x01010101, 0x13131313, 0x8a8a8a8a, 0x6b6b6b6b, + 0x3a3a3a3a, 0x91919191, 0x11111111, 0x41414141, 0x4f4f4f4f, 0x67676767, 0xdcdcdcdc, 0xeaeaeaea, + 0x97979797, 0xf2f2f2f2, 0xcfcfcfcf, 0xcececece, 0xf0f0f0f0, 0xb4b4b4b4, 0xe6e6e6e6, 0x73737373, + 0x96969696, 0xacacacac, 0x74747474, 0x22222222, 0xe7e7e7e7, 0xadadadad, 0x35353535, 0x85858585, + 0xe2e2e2e2, 0xf9f9f9f9, 0x37373737, 0xe8e8e8e8, 0x1c1c1c1c, 0x75757575, 0xdfdfdfdf, 0x6e6e6e6e, + 0x47474747, 0xf1f1f1f1, 0x1a1a1a1a, 0x71717171, 0x1d1d1d1d, 0x29292929, 0xc5c5c5c5, 0x89898989, + 0x6f6f6f6f, 0xb7b7b7b7, 0x62626262, 0x0e0e0e0e, 0xaaaaaaaa, 0x18181818, 0xbebebebe, 0x1b1b1b1b, + 0xfcfcfcfc, 0x56565656, 0x3e3e3e3e, 0x4b4b4b4b, 0xc6c6c6c6, 0xd2d2d2d2, 0x79797979, 0x20202020, + 0x9a9a9a9a, 0xdbdbdbdb, 0xc0c0c0c0, 0xfefefefe, 0x78787878, 0xcdcdcdcd, 0x5a5a5a5a, 0xf4f4f4f4, + 0x1f1f1f1f, 0xdddddddd, 0xa8a8a8a8, 0x33333333, 0x88888888, 0x07070707, 0xc7c7c7c7, 0x31313131, + 0xb1b1b1b1, 0x12121212, 0x10101010, 0x59595959, 0x27272727, 0x80808080, 0xecececec, 0x5f5f5f5f, + 0x60606060, 0x51515151, 0x7f7f7f7f, 0xa9a9a9a9, 0x19191919, 0xb5b5b5b5, 0x4a4a4a4a, 0x0d0d0d0d, + 0x2d2d2d2d, 0xe5e5e5e5, 0x7a7a7a7a, 0x9f9f9f9f, 0x93939393, 0xc9c9c9c9, 0x9c9c9c9c, 0xefefefef, + 0xa0a0a0a0, 0xe0e0e0e0, 0x3b3b3b3b, 0x4d4d4d4d, 0xaeaeaeae, 0x2a2a2a2a, 0xf5f5f5f5, 0xb0b0b0b0, + 0xc8c8c8c8, 0xebebebeb, 0xbbbbbbbb, 0x3c3c3c3c, 0x83838383, 0x53535353, 0x99999999, 0x61616161, + 0x17171717, 0x2b2b2b2b, 0x04040404, 0x7e7e7e7e, 0xbabababa, 0x77777777, 0xd6d6d6d6, 0x26262626, + 0xe1e1e1e1, 0x69696969, 0x14141414, 0x63636363, 0x55555555, 0x21212121, 0x0c0c0c0c, 0x7d7d7d7d, +) + +_RCON = ( + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, # for 128-bit blocks, Rijndael never uses more than 10 rcon values +) + + +def _rijndaelKeySetupEnc(key: bytes) -> typing.Tuple[int]: + """Expand the cipher key into the encryption key schedule.""" + keylen = len(key) + if keylen == 16: + rc = 10 + rk = [0] * (rc + 1) * 4 + rk[:4] = struct.unpack(">IIII", key) + for i in range(0, len(rk) - 4, 4): + temp = rk[i + 3] + rk[i + 4] = rk[i + 0] \ + ^ (_TE4[(temp >> 16) & 0xff] & 0xff000000) \ + ^ (_TE4[(temp >> 8) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(temp ) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(temp >> 24) ] & 0x000000ff) \ + ^_RCON[i // 4] + rk[i + 5] = rk[i + 1] ^ rk[i + 4] + rk[i + 6] = rk[i + 2] ^ rk[i + 5] + rk[i + 7] = rk[i + 3] ^ rk[i + 6] + elif keylen == 24: + rc = 12 + rk = [0] * (rc + 1) * 4 + rk[:6] = struct.unpack(">IIIIII", key) + for i in range(0, len(rk) - 6, 6): + temp = rk[i + 5] + rk[i + 6] = rk[i + 0] \ + ^ (_TE4[(temp >> 16) & 0xff] & 0xff000000) \ + ^ (_TE4[(temp >> 8) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(temp ) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(temp >> 24) ] & 0x000000ff) \ + ^_RCON[i // 6] + rk[i + 7] = rk[i + 1] ^ rk[i + 6] + rk[i + 8] = rk[i + 2] ^ rk[i + 7] + rk[i + 9] = rk[i + 3] ^ rk[i + 8] + if i // 6 == 7: + break + rk[i + 10] = rk[i + 4] ^ rk[i + 9] + rk[i + 11] = rk[i + 5] ^ rk[i + 10] + elif keylen == 32: + rc = 14 + rk = [0] * (rc + 1) * 4 + rk[:8] = struct.unpack(">IIIIIIII", key) + for i in range(0, len(rk) - 8, 8): + temp = rk[i + 7] + rk[i + 8] = rk[i + 0] \ + ^ (_TE4[(temp >> 16) & 0xff] & 0xff000000) \ + ^ (_TE4[(temp >> 8) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(temp ) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(temp >> 24) ] & 0x000000ff) \ + ^_RCON[i // 8] + rk[i + 9] = rk[i + 1] ^ rk[i + 8] + rk[i + 10] = rk[i + 2] ^ rk[i + 9] + rk[i + 11] = rk[i + 3] ^ rk[i + 10] + if i // 8 == 6: + break + temp = rk[i + 11] + rk[i + 12] = rk[i + 4] \ + ^ (_TE4[(temp >> 24) ] & 0xff000000) \ + ^ (_TE4[(temp >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(temp >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(temp ) & 0xff] & 0x000000ff) + rk[i + 13] = rk[i + 5] ^ rk[i + 12] + rk[i + 14] = rk[i + 6] ^ rk[i + 13] + rk[i + 15] = rk[i + 7] ^ rk[i + 14] + else: + raise ValueError("invalid key size: {}, must be one of (128, 192, 256)!".format(keylen * 8)) + + return tuple(rk) + + +def _rijndaelKeySetupDec(rk: typing.Tuple[int]) -> typing.Tuple[int]: + """Expand the cipher key into the decryption key schedule.""" + # expand the cipher key: + rk = list(rk) + # invert the order of the round keys: + xl = len(rk) + i, j = 0, xl - 4 + while i < j: + temp = rk[i:i + 4] + rk[i:i + 4] = rk[j:j + 4] + rk[j:j + 4] = temp + i += 4 + j -= 4 + # apply the inverse MixColumn transform to all round keys but the first and the last: + for i in range(4, xl - 4, 4): + rk[i + 0] = \ + _TD0[_TE4[(rk[i + 0] >> 24)] & 0xff] \ + ^ _TD1[_TE4[(rk[i + 0] >> 16) & 0xff] & 0xff] \ + ^ _TD2[_TE4[(rk[i + 0] >> 8) & 0xff] & 0xff] \ + ^ _TD3[_TE4[(rk[i + 0] ) & 0xff] & 0xff] + rk[i + 1] = \ + _TD0[_TE4[(rk[i + 1] >> 24)] & 0xff] \ + ^ _TD1[_TE4[(rk[i + 1] >> 16) & 0xff] & 0xff] \ + ^ _TD2[_TE4[(rk[i + 1] >> 8) & 0xff] & 0xff] \ + ^ _TD3[_TE4[(rk[i + 1] ) & 0xff] & 0xff] + rk[i + 2] = \ + _TD0[_TE4[(rk[i + 2] >> 24)] & 0xff] \ + ^ _TD1[_TE4[(rk[i + 2] >> 16) & 0xff] & 0xff] \ + ^ _TD2[_TE4[(rk[i + 2] >> 8) & 0xff] & 0xff] \ + ^ _TD3[_TE4[(rk[i + 2] ) & 0xff] & 0xff] + rk[i + 3] = \ + _TD0[_TE4[(rk[i + 3] >> 24)] & 0xff] \ + ^ _TD1[_TE4[(rk[i + 3] >> 16) & 0xff] & 0xff] \ + ^ _TD2[_TE4[(rk[i + 3] >> 8) & 0xff] & 0xff] \ + ^ _TD3[_TE4[(rk[i + 3] ) & 0xff] & 0xff] + return tuple(rk) + + +def _rijndaelEncrypt(rk: typing.Tuple[int], text: bytes): + rc = len(rk) // 4 - 1 # round + + # map byte array block to cipher state and add initial round key: + ss = struct.unpack(">IIII", text) + s0 = ss[0] ^ rk[0] + s1 = ss[1] ^ rk[1] + s2 = ss[2] ^ rk[2] + s3 = ss[3] ^ rk[3] + + # round 1: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[ 4] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[ 5] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[ 6] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[ 7] + # round 2: + s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[ 8] + s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[ 9] + s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[10] + s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[11] + # round 3: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[12] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[13] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[14] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[15] + # round 4: + s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[16] + s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[17] + s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[18] + s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[19] + # round 5: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[20] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[21] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[22] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[23] + # round 6: + s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[24] + s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[25] + s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[26] + s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[27] + # round 7: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[28] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[29] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[30] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[31] + # round 8: + s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[32] + s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[33] + s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[34] + s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[35] + # round 9: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[36] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[37] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[38] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[39] + if rc > 10: + # round 10: + s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[40] + s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[41] + s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[42] + s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[43] + # round 11: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[44] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[45] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[46] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[47] + if rc > 12: + # round 12: + s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[48] + s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[49] + s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[50] + s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[51] + # round 13: + t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[52] + t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[53] + t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[54] + t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[55] + + # apply last round and map cipher state to byte array block: + s0 = rk[-4] \ + ^ (_TE4[(t0 >> 24) ] & 0xff000000) \ + ^ (_TE4[(t1 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(t2 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(t3 ) & 0xff] & 0x000000ff) + s1 = rk[-3] \ + ^ (_TE4[(t1 >> 24) ] & 0xff000000) \ + ^ (_TE4[(t2 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(t3 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(t0 ) & 0xff] & 0x000000ff) + s2 = rk[-2] \ + ^ (_TE4[(t2 >> 24) ] & 0xff000000) \ + ^ (_TE4[(t3 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(t0 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(t1 ) & 0xff] & 0x000000ff) + s3 = rk[-1] \ + ^ (_TE4[(t3 >> 24) ] & 0xff000000) \ + ^ (_TE4[(t0 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TE4[(t1 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TE4[(t2 ) & 0xff] & 0x000000ff) + + return struct.pack(">IIII", s0, s1, s2, s3) + + +def _rijndaelDecrypt(rk: typing.Tuple[int], data: bytes) -> bytes: + rc = len(rk) // 4 - 1 # round + + # map byte array block to cipher state and add initial round key: + ss = struct.unpack(">IIII", data) + s0 = ss[0] ^ rk[0] + s1 = ss[1] ^ rk[1] + s2 = ss[2] ^ rk[2] + s3 = ss[3] ^ rk[3] + + # round 1: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[ 4] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[ 5] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[ 6] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[ 7] + # round 2: + s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[ 8] + s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[ 9] + s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[10] + s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[11] + # round 3: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[12] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[13] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[14] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[15] + # round 4: + s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[16] + s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[17] + s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[18] + s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[19] + # round 5: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[20] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[21] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[22] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[23] + # round 6: + s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[24] + s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[25] + s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[26] + s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[27] + # round 7: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[28] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[29] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[30] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[31] + # round 8: + s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[32] + s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[33] + s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[34] + s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[35] + # round 9: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[36] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[37] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[38] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[39] + if rc > 10: + # round 10: + s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[40] + s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[41] + s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[42] + s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[43] + # round 11: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[44] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[45] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[46] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[47] + if rc > 12: + # round 12: + s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[48] + s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[49] + s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[50] + s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[51] + # round 13: + t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[52] + t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[53] + t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[54] + t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[55] + + # apply last round and map cipher state to byte array block: + s0 = rk[-4] \ + ^ (_TD4[(t0 >> 24) ] & 0xff000000) \ + ^ (_TD4[(t3 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TD4[(t2 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TD4[(t1 ) & 0xff] & 0x000000ff) + s1 = rk[-3] \ + ^ (_TD4[(t1 >> 24) ] & 0xff000000) \ + ^ (_TD4[(t0 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TD4[(t3 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TD4[(t2 ) & 0xff] & 0x000000ff) + s2 = rk[-2] \ + ^ (_TD4[(t2 >> 24) ] & 0xff000000) \ + ^ (_TD4[(t1 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TD4[(t0 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TD4[(t3 ) & 0xff] & 0x000000ff) + s3 = rk[-1] \ + ^ (_TD4[(t3 >> 24) ] & 0xff000000) \ + ^ (_TD4[(t2 >> 16) & 0xff] & 0x00ff0000) \ + ^ (_TD4[(t1 >> 8) & 0xff] & 0x0000ff00) \ + ^ (_TD4[(t0 ) & 0xff] & 0x000000ff) + + return struct.pack(">IIII", s0, s1, s2, s3) + + +class _AES: + def __init__(self, key: bytes) -> None: + self._ek = _rijndaelKeySetupEnc(key) + self._dk = _rijndaelKeySetupDec(self._ek) + + def encrypt(self, data: bytes) -> bytes: + return _rijndaelEncrypt(self._ek, data) + + def decrypt(self, data: bytes) -> bytes: + return _rijndaelDecrypt(self._dk, data) + + +class AESCBC: + def __init__(self, key: bytes) -> None: + self._ek = _rijndaelKeySetupEnc(key) + self._dk = _rijndaelKeySetupDec(self._ek) + + def encrypt(self, iv: bytes, data: bytes) -> bytes: + cc = bytes(iv) # in case bytearray + ee = b"" + xl = len(data) + for i in range(0, xl, 16): + dd = bytes(bytearray(cc[j] ^ data[i + j] for j in range(16))) + cc = _rijndaelEncrypt(self._ek, dd) + ee += cc + return ee + + def decrypt(self, iv: bytes, data: bytes) -> bytes: + cc = bytes(iv) # in case bytearray + dd = b"" + xl = len(data) + for i in range(0, xl, 16): + xx = _rijndaelDecrypt(self._dk, data[i:i + 16]) + dd += bytes(bytearray(cc[j] ^ xx[j] for j in range(16))) + cc = data[i:i + 16] + return dd + + +def _test(): + key128 = b"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c" + rk_128 = ( + 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c, 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605, + 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f, 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b, + 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00, 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc, + 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd, 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f, + 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f, 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e, + 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6, + ) + assert rk_128 == _rijndaelKeySetupEnc(key128) + + key192 = b"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b" + rk_192 = ( + 0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5, 0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5, + 0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2, 0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd, + 0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f, 0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6, + 0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767, 0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971, + 0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3, 0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e, + 0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753, 0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5, + 0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202, + ) + assert rk_192 == _rijndaelKeySetupEnc(key192) + + key256 = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4" + rk_256 = ( + 0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781, 0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4, + 0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde, 0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a, + 0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96, 0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3, + 0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464, 0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214, + 0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80, 0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239, + 0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15, 0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3, + 0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a, 0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d, + 0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e, + ) + assert rk_256 == _rijndaelKeySetupEnc(key256) + + # test for encrypt / decrypt + import random + from Crypto.Cipher import AES as PyCryptoAES + + def _test_enc_dec(aes0, aes1, pp): + e0 = aes0.encrypt(pp) + d0 = aes0.decrypt(e0) + + e1 = aes1.encrypt(pp) + d1 = aes1.decrypt(e1) + + assert pp == d0 == d1 + assert e0 == e1 + + aes128_0 = _AES(key128) + aes192_0 = _AES(key192) + aes256_0 = _AES(key256) + + aes128_1 = PyCryptoAES.new(key128, PyCryptoAES.MODE_ECB) + aes192_1 = PyCryptoAES.new(key192, PyCryptoAES.MODE_ECB) + aes256_1 = PyCryptoAES.new(key256, PyCryptoAES.MODE_ECB) + + for _ in range(10): + pp = bytes(bytearray(random.randint(0, 255) for _ in range(16))) + _test_enc_dec(aes128_0, aes128_1, pp) + _test_enc_dec(aes192_0, aes192_1, pp) + _test_enc_dec(aes256_0, aes256_1, pp) + + def _test_CBC(key, iv, pp): + aes0 = AESCBC(key) + e0 = aes0.encrypt(iv, pp) + d0 = aes0.decrypt(iv, e0) + + e1 = PyCryptoAES.new(key, PyCryptoAES.MODE_CBC, iv=iv).encrypt(pp) + d1 = PyCryptoAES.new(key, PyCryptoAES.MODE_CBC, iv=iv).decrypt(e1) + + assert pp == d0 == d1 + assert e0 == e1 + + for _ in range(10): + iv = bytes(bytearray(random.randint(0, 255) for _ in range(16))) + pp = bytes(bytearray(random.randint(0, 255) for _ in range(16 * 4))) + _test_CBC(key128, iv, pp) + _test_CBC(key192, iv, pp) + _test_CBC(key256, iv, pp) + + +if __name__ == "__main__": + _test() diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index 889e76006..93a7bc9d3 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -72,6 +72,8 @@ def decrypt(self, data: bytes) -> bytes: except ImportError: + from PyPDF2._aes import AESCBC + class CryptRC4(CryptBase): def __init__(self, key: bytes) -> None: self.S = list(range(256)) @@ -97,13 +99,19 @@ def decrypt(self, data: bytes) -> bytes: class CryptAES(CryptBase): def __init__(self, key: bytes) -> None: - self.key = key + self.aes = AESCBC(key) def encrypt(self, data: bytes) -> bytes: - raise RuntimeError("PyCryptodome is required for AES encryption") + iv = bytes(bytearray(random.randint(0, 255) for _ in range(16))) + p = 16 - len(data) % 16 + data += bytes(bytearray(p for _ in range(p))) + return iv + self.aes.encrypt(iv, data) def decrypt(self, data: bytes) -> bytes: - raise RuntimeError("PyCryptodome is required for AES decryption") + iv = data[:16] + data = data[16:] + d = self.aes.decrypt(iv, data) + return d[:-d[-1]] class CryptIdentity(CryptBase): diff --git a/tox.ini b/tox.ini index 41fd77955..517e48eba 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,6 @@ envlist = [testenv] deps = - PyCryptodome pillow pytest pytest-cov From 46e1da31f70892281cbecbbbf4dba595b04e8bad Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Sat, 16 Apr 2022 12:16:09 +0800 Subject: [PATCH 04/13] FIX: allow use owner password to decrypt --- PyPDF2/pdf.py | 2 +- Resources/encryption/enca.pdf | Bin 0 -> 16395 bytes Resources/encryption/encb.pdf | Bin 0 -> 16395 bytes Tests/test_encryption.py | 12 +++++++++--- 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 Resources/encryption/enca.pdf create mode 100644 Resources/encryption/encb.pdf diff --git a/PyPDF2/pdf.py b/PyPDF2/pdf.py index 58faabbfe..0a586d4cb 100644 --- a/PyPDF2/pdf.py +++ b/PyPDF2/pdf.py @@ -2086,7 +2086,7 @@ def _decrypt(self, password): o_entry = encryptEntry["/O"].getObject().original_bytes # maybe password is owner password # TODO: add/modify api to set owner password - rr = encryption.decryptPdf(u_entry, o_entry, password, "") + rr = encryption.decryptPdf(u_entry, o_entry, password, password) if rr > 0: self._encryption = encryption return rr diff --git a/Resources/encryption/enca.pdf b/Resources/encryption/enca.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1a9d32570beee3fa73c72fbd4f9aa781677d01b9 GIT binary patch literal 16395 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 M>c$NvZDp$e2Yr;pF#rGn literal 0 HcmV?d00001 diff --git a/Resources/encryption/encb.pdf b/Resources/encryption/encb.pdf new file mode 100644 index 0000000000000000000000000000000000000000..900c151d153b0d06330945f52a8abac0590b1410 GIT binary patch literal 16395 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 Q5CjH{pcfHQH_)K}fAp2+1poj5 literal 0 HcmV?d00001 diff --git a/Tests/test_encryption.py b/Tests/test_encryption.py index 69ac66996..ddbf89e92 100644 --- a/Tests/test_encryption.py +++ b/Tests/test_encryption.py @@ -29,12 +29,18 @@ (os.path.join(RESOURCE_ROOT, "encryption", "enc6.pdf")), # # V=5 and AES256 (TODO) - # # created by `qpdf --encrypt "" "" 256 -- enc0.pdf enc6.pdf` + # # created by `qpdf --encrypt "" "" 256 -- enc0.pdf enc7.pdf` # (os.path.join(RESOURCE_ROOT, "encryption", "enc7.pdf")), - # # created by `qpdf --encrypt "asdfzxcv" "" 256 -- enc0.pdf enc6.pdf` + # # created by `qpdf --encrypt "asdfzxcv" "" 256 -- enc0.pdf enc8.pdf` # (os.path.join(RESOURCE_ROOT, "encryption", "enc8.pdf")), - # # created by `qpdf --encrypt "" "asdfzxcv" 256 -- enc0.pdf enc6.pdf` + # # created by `qpdf --encrypt "" "asdfzxcv" 256 -- enc0.pdf enc9.pdf` # (os.path.join(RESOURCE_ROOT, "encryption", "enc9.pdf")), + + # asdfzxcv is owner password + # created by `qpdf --encrypt "" "asdfzxcv" 128 --use-aes=y -- enc0.pdf enca.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enca.pdf")), + # created by `qpdf --encrypt "1234" "asdfzxcv" 128 --use-aes=y -- enc0.pdf encb.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "encb.pdf")), ], ) def test_encryption(src): From 970125efbe730d0441391fd48809ada09d687922 Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Sat, 16 Apr 2022 12:16:57 +0800 Subject: [PATCH 05/13] FIX: merge encrypted pdf --- PyPDF2/merger.py | 10 +++++----- Tests/test_encryption.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/PyPDF2/merger.py b/PyPDF2/merger.py index 1f2ab2d6b..9e6f0171e 100644 --- a/PyPDF2/merger.py +++ b/PyPDF2/merger.py @@ -115,7 +115,7 @@ def merge(self, position, fileobj, bookmark=None, pages=None, import_bookmarks=T # it is a PdfFileReader, copy that reader's stream into a # BytesIO (or StreamIO) stream. # If fileobj is none of the above types, it is not modified - decryption_key = None + _encryption = None if isString(fileobj): fileobj = file(fileobj, 'rb') my_file = True @@ -125,8 +125,8 @@ def merge(self, position, fileobj, bookmark=None, pages=None, import_bookmarks=T fileobj = StreamIO(filecontent) my_file = True elif isinstance(fileobj, PdfFileReader): - if hasattr(fileobj, '_decryption_key'): - decryption_key = fileobj._decryption_key + if hasattr(fileobj, '_encryption'): + _encryption = fileobj._encryption orig_tell = fileobj.stream.tell() fileobj.stream.seek(0) filecontent = StreamIO(fileobj.stream.read()) @@ -137,8 +137,8 @@ def merge(self, position, fileobj, bookmark=None, pages=None, import_bookmarks=T # Create a new PdfFileReader instance using the stream # (either file or BytesIO or StringIO) created above pdfr = PdfFileReader(fileobj, strict=self.strict, overwriteWarnings=self.overwriteWarnings) - if decryption_key is not None: - pdfr._decryption_key = decryption_key + if _encryption is not None: + pdfr._encryption = _encryption # Find the range of pages to merge. if pages is None: diff --git a/Tests/test_encryption.py b/Tests/test_encryption.py index ddbf89e92..8e3586546 100644 --- a/Tests/test_encryption.py +++ b/Tests/test_encryption.py @@ -64,3 +64,21 @@ def test_encryption(src): '/SourceModified': "D:20220414132421+05'24'", '/Trapped': '/False' } + + +@pytest.mark.parametrize( + "names", + [ + (["enc0.pdf", "enc4.pdf", "enc5.pdf", "enc6.pdf"]), + ], +) +def test_encryption_merge(names): + pdf_merger = PyPDF2.PdfFileMerger() + files = [os.path.join(RESOURCE_ROOT, "encryption", x) for x in names] + pdfs = [PyPDF2.PdfFileReader(x) for x in files] + for pdf in pdfs: + if pdf.isEncrypted: + pdf.decrypt("asdfzxcv") + pdf_merger.append(pdf) + # no need to write to file + pdf_merger.close() From 47cfbd581690edb69eb8395afe747be62b78c3b6 Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Mon, 18 Apr 2022 14:35:26 +0800 Subject: [PATCH 06/13] decrypt support V=5 and R=5, which uses AES-256 --- PyPDF2/_aes.py | 20 +- PyPDF2/encryption.py | 612 +++++++++++++++++++++++----------- PyPDF2/pdf.py | 9 +- Resources/encryption/enc7.pdf | Bin 16709 -> 16709 bytes Resources/encryption/enc8.pdf | Bin 16709 -> 16709 bytes Resources/encryption/enc9.pdf | Bin 16709 -> 16709 bytes Tests/test_encryption.py | 14 +- 7 files changed, 445 insertions(+), 210 deletions(-) diff --git a/PyPDF2/_aes.py b/PyPDF2/_aes.py index 7eb486e1c..0f78aea21 100644 --- a/PyPDF2/_aes.py +++ b/PyPDF2/_aes.py @@ -695,16 +695,22 @@ def _rijndaelDecrypt(rk: typing.Tuple[int], data: bytes) -> bytes: return struct.pack(">IIII", s0, s1, s2, s3) -class _AES: +class AESECB: def __init__(self, key: bytes) -> None: self._ek = _rijndaelKeySetupEnc(key) self._dk = _rijndaelKeySetupDec(self._ek) def encrypt(self, data: bytes) -> bytes: - return _rijndaelEncrypt(self._ek, data) + ee = [] + for i in range(0, len(data), 16): + ee.append(_rijndaelEncrypt(self._ek, data[i:i + 16])) + return b"".join(ee) def decrypt(self, data: bytes) -> bytes: - return _rijndaelDecrypt(self._dk, data) + dd = [] + for i in range(0, len(data), 16): + dd.append(_rijndaelDecrypt(self._dk, data[i:i + 16])) + return b"".join(dd) class AESCBC: @@ -784,16 +790,16 @@ def _test_enc_dec(aes0, aes1, pp): assert pp == d0 == d1 assert e0 == e1 - aes128_0 = _AES(key128) - aes192_0 = _AES(key192) - aes256_0 = _AES(key256) + aes128_0 = AESECB(key128) + aes192_0 = AESECB(key192) + aes256_0 = AESECB(key256) aes128_1 = PyCryptoAES.new(key128, PyCryptoAES.MODE_ECB) aes192_1 = PyCryptoAES.new(key192, PyCryptoAES.MODE_ECB) aes256_1 = PyCryptoAES.new(key256, PyCryptoAES.MODE_ECB) for _ in range(10): - pp = bytes(bytearray(random.randint(0, 255) for _ in range(16))) + pp = bytes(bytearray(random.randint(0, 255) for _ in range(32))) _test_enc_dec(aes128_0, aes128_1, pp) _test_enc_dec(aes192_0, aes192_1, pp) _test_enc_dec(aes256_0, aes256_1, pp) diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index 93a7bc9d3..b7ecadc2e 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -39,6 +39,10 @@ class CryptBase: def encrypt(self, data: bytes) -> bytes: return data def decrypt(self, data: bytes) -> bytes: return data + +class CryptIdentity(CryptBase): pass + + try: from Crypto.Cipher import ARC4, AES @@ -70,9 +74,27 @@ def decrypt(self, data: bytes) -> bytes: 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) + except ImportError: - from PyPDF2._aes import AESCBC + from PyPDF2._aes import AESECB, AESCBC class CryptRC4(CryptBase): def __init__(self, key: bytes) -> None: @@ -113,9 +135,48 @@ def decrypt(self, data: bytes) -> bytes: d = self.aes.decrypt(iv, data) return d[:-d[-1]] + def RC4_encrypt(key: bytes, data: bytes) -> bytes: + return CryptRC4(key).encrypt(data) -class CryptIdentity(CryptBase): - pass + def RC4_decrypt(key: bytes, data: bytes) -> bytes: + return CryptRC4(key).decrypt(data) + + def AES_ECB_encrypt(key: bytes, data: bytes) -> bytes: + return AESECB(key).encrypt(data) + + def AES_ECB_decrypt(key: bytes, data: bytes) -> bytes: + return AESECB(key).decrypt(data) + + def AES_CBC_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + return AESCBC(key).encrypt(iv, data) + + def AES_CBC_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: + return AESCBC(key).decrypt(iv, data) + + +class CryptFilter: + def __init__(self, stmCrypt: CryptBase, strCrypt: CryptBase, efCrypt: CryptBase) -> None: + self.stmCrypt = stmCrypt + self.strCrypt = strCrypt + self.efCrypt = efCrypt + + def encryptObject(self, obj: PdfObject) -> PdfObject: + # TODO + return NotImplemented + + def decryptObject(self, obj: PdfObject) -> PdfObject: + if isinstance(obj, ByteStringObject) or isinstance(obj, TextStringObject): + data = self.strCrypt.decrypt(obj.original_bytes) + obj = createStringObject(data) + elif isinstance(obj, StreamObject): + obj._data = self.stmCrypt.decrypt(obj._data) + elif isinstance(obj, DictionaryObject): + for dictkey, value in list(obj.items()): + obj[dictkey] = self.decryptObject(value) + elif isinstance(obj, ArrayObject): + for i in range(len(obj)): + obj[i] = self.decryptObject(obj[i]) + return obj _PADDING = bytes([ @@ -135,157 +196,139 @@ def _bytes(text: str) -> bytes: return text.encode('utf-8') -class StandardSecurityHandler: - def __init__(self, rev: int, perm: int, keylen: int, metadata_encrypted: bool, first_id_entry: bytes) -> None: - self.R = rev - self.P = (perm + 0x100000000) % 0x100000000 # maybe < 0 - self.Length = keylen - self.metadata_encrypted = metadata_encrypted - self.id1_entry = first_id_entry if first_id_entry is not None else b"" - - self.key: typing.Optional[bytes] = None - - def generate(self, user_pwd: str, owner_pwd: str=None) -> typing.Tuple[bytes, bytes]: - u_entry = self._compute_U_value(user_pwd, owner_pwd) - o_entry = self._compute_O_value(user_pwd, owner_pwd) - return u_entry, o_entry - - def auth(self, u_entry: bytes, o_entry: bytes, user_pwd: str, owner_pwd: str=None) -> int: - if self._auth_user_password(u_entry, o_entry, user_pwd): - return 1 - elif self._auth_owner_password(u_entry, o_entry, owner_pwd): - return 2 - else: - self.key = None - return 0 - - def _compute_key(self, password: bytes, o_entry: bytes) -> bytes: +class AlgR4: + @staticmethod + def compute_key(password: bytes, rev: int, key_size: int, o_entry: bytes, P: int, id1_entry: bytes, metadata_encrypted: bool) -> bytes: """ Algorithm 2: Computing an encryption key - """ - """ a) Pad or truncate the password string to exactly 32 bytes. If the password string is more than 32 bytes long, - use only its first 32 bytes; if it is less than 32 bytes long, pad it by appending the required number of - additional bytes from the beginning of the following padding string: - < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 - 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A > - That is, if the password string is n bytes long, append the first 32 - n bytes of the padding string to the end - of the password string. If the password string is empty (zero-length), meaning there is no user password, - substitute the entire padding string in its place. + a) Pad or truncate the password string to exactly 32 bytes. If the password string is more than 32 bytes long, + use only its first 32 bytes; if it is less than 32 bytes long, pad it by appending the required number of + additional bytes from the beginning of the following padding string: + < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 + 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A > + That is, if the password string is n bytes long, append the first 32 - n bytes of the padding string to the end + of the password string. If the password string is empty (zero-length), meaning there is no user password, + substitute the entire padding string in its place. + + b) Initialize the MD5 hash function and pass the result of step (a) as input to this function. + c) Pass the value of the encryption dictionary’s O entry to the MD5 hash function. ("Algorithm 3: Computing + the encryption dictionary’s O (owner password) value" shows how the O value is computed.) + d) Convert the integer value of the P entry to a 32-bit unsigned binary number and pass these bytes to the + MD5 hash function, low-order byte first. + e) Pass the first element of the file’s file identifier array (the value of the ID entry in the document’s trailer + dictionary; see Table 15) to the MD5 hash function. + f) (Security handlers of revision 4 or greater) If document metadata is not being encrypted, pass 4 bytes with + the value 0xFFFFFFFF to the MD5 hash function. + g) Finish the hash. + h) (Security handlers of revision 3 or greater) Do the following 50 times: Take the output from the previous + MD5 hash and pass the first n bytes of the output as input into a new MD5 hash, where n is the number of + bytes of the encryption key as defined by the value of the encryption dictionary’s Length entry. + i) Set the encryption key to the first n bytes of the output from the final MD5 hash, where n shall always be 5 + for security handlers of revision 2 but, for security handlers of revision 3 or greater, shall depend on the + value of the encryption dictionary’s Length entry. """ a = _padding(password) - """ b) Initialize the MD5 hash function and pass the result of step (a) as input to this function. """ u_hash = hashlib.md5(a) - """ c) Pass the value of the encryption dictionary’s O entry to the MD5 hash function. ("Algorithm 3: Computing - the encryption dictionary’s O (owner password) value" shows how the O value is computed.) - """ u_hash.update(o_entry) - """ d) Convert the integer value of the P entry to a 32-bit unsigned binary number and pass these bytes to the - MD5 hash function, low-order byte first. - """ - u_hash.update(struct.pack('= 3 and not self.metadata_encrypted: + u_hash.update(struct.pack('= 3 and not metadata_encrypted: u_hash.update(b"\xff\xff\xff\xff") - """ g) Finish the hash. """ u_hash_digest = u_hash.digest() - """ h) (Security handlers of revision 3 or greater) Do the following 50 times: Take the output from the previous - MD5 hash and pass the first n bytes of the output as input into a new MD5 hash, where n is the number of - bytes of the encryption key as defined by the value of the encryption dictionary’s Length entry. - """ - length = self.Length // 8 - if self.R >= 3: + length = key_size // 8 + if rev >= 3: for _ in range(50): u_hash_digest = hashlib.md5(u_hash_digest[:length]).digest() - """ i) Set the encryption key to the first n bytes of the output from the final MD5 hash, where n shall always be 5 - for security handlers of revision 2 but, for security handlers of revision 3 or greater, shall depend on the - value of the encryption dictionary’s Length entry. - """ return u_hash_digest[:length] - def _compute_O_value(self, user_pwd: bytes, owner_pwd: bytes=None) -> bytes: + @staticmethod + def compute_O_value_key(owner_pwd: bytes, rev: int, key_size: int) -> bytes: """ Algorithm 3: Computing the encryption dictionary’s O (owner password) value - """ - """ a) Pad or truncate the owner password string as described in step (a) of "Algorithm 2: Computing an - encryption key". If there is no owner password, use the user password instead. + a) Pad or truncate the owner password string as described in step (a) of "Algorithm 2: Computing an + encryption key". If there is no owner password, use the user password instead. + b) Initialize the MD5 hash function and pass the result of step (a) as input to this function. + c) (Security handlers of revision 3 or greater) Do the following 50 times: Take the output from the previous + MD5 hash and pass it as input into a new MD5 hash. + d) Create an RC4 encryption key using the first n bytes of the output from the final MD5 hash, where n shall + always be 5 for security handlers of revision 2 but, for security handlers of revision 3 or greater, shall + depend on the value of the encryption dictionary’s Length entry. + e) Pad or truncate the user password string as described in step (a) of "Algorithm 2: Computing an encryption key". + f) Encrypt the result of step (e), using an RC4 encryption function with the encryption key obtained in step (d). + g) (Security handlers of revision 3 or greater) Do the following 19 times: Take the output from the previous + invocation of the RC4 function and pass it as input to a new invocation of the function; use an encryption + key generated by taking each byte of the encryption key obtained in step (d) and performing an XOR + (exclusive or) operation between that byte and the single-byte value of the iteration counter (from 1 to 19). + h) Store the output from the final invocation of the RC4 function as the value of the O entry in the encryption + dictionary. """ - a = _padding(owner_pwd if owner_pwd else user_pwd) - """ b) Initialize the MD5 hash function and pass the result of step (a) as input to this function. """ + + a = _padding(owner_pwd) o_hash_digest = hashlib.md5(a).digest() - """ c) (Security handlers of revision 3 or greater) Do the following 50 times: Take the output from the previous - MD5 hash and pass it as input into a new MD5 hash. """ - if self.R >= 3: + + if rev >= 3: for _ in range(50): o_hash_digest = hashlib.md5(o_hash_digest).digest() - """ d) Create an RC4 encryption key using the first n bytes of the output from the final MD5 hash, where n shall - always be 5 for security handlers of revision 2 but, for security handlers of revision 3 or greater, shall - depend on the value of the encryption dictionary’s Length entry. - """ - rc4_key = o_hash_digest[:self.Length // 8] - """ e) Pad or truncate the user password string as described in step (a) of "Algorithm 2: Computing an encryption key". """ + + rc4_key = o_hash_digest[:key_size // 8] + return rc4_key + + @staticmethod + def compute_O_value(rc4_key: bytes, user_pwd: bytes, rev: int) -> bytes: + """see :func:`compute_O_value_key`""" a = _padding(user_pwd) - """ f) Encrypt the result of step (e), using an RC4 encryption function with the encryption key obtained in step (d). """ - rc4_enc = CryptRC4(rc4_key).encrypt(a) - """ g) (Security handlers of revision 3 or greater) Do the following 19 times: Take the output from the previous - invocation of the RC4 function and pass it as input to a new invocation of the function; use an encryption - key generated by taking each byte of the encryption key obtained in step (d) and performing an XOR - (exclusive or) operation between that byte and the single-byte value of the iteration counter (from 1 to 19). - """ - if self.R >= 3: + rc4_enc = RC4_encrypt(rc4_key, a) + if rev >= 3: for i in range(1, 20): key = bytes(bytearray([x ^ i for x in rc4_key])) - rc4_enc = CryptRC4(key).encrypt(rc4_enc) - """ h) Store the output from the final invocation of the RC4 function as the value of the O entry in the encryption dictionary. """ + rc4_enc = RC4_encrypt(key, rc4_enc) return rc4_enc - def _compute_U_value(self, user_pwd: bytes, o_entry: bytes) -> bytes: + @staticmethod + def compute_U_value(key: bytes, rev: int, id1_entry: bytes) -> bytes: """ Algorithm 4: Computing the encryption dictionary’s U (user password) value (Security handlers of revision 2) + + a) Create an encryption key based on the user password string, as described in "Algorithm 2: Computing an + encryption key". + b) Encrypt the 32-byte padding string shown in step (a) of "Algorithm 2: Computing an encryption key", using + an RC4 encryption function with the encryption key from the preceding step. + c) Store the result of step (b) as the value of the U entry in the encryption dictionary. """ - """ a) Create an encryption key based on the user password string, as described in "Algorithm 2: Computing an encryption key". """ - self.key = self._compute_key(user_pwd, o_entry) - """ b) Encrypt the 32-byte padding string shown in step (a) of "Algorithm 2: Computing an encryption key", using - an RC4 encryption function with the encryption key from the preceding step. - c) Store the result of step (b) as the value of the U entry in the encryption dictionary. - """ - if self.R <= 2: - value = CryptRC4(self.key).encrypt(_PADDING) + if rev <= 2: + value = RC4_encrypt(key, _PADDING) return value """ Algorithm 5: Computing the encryption dictionary’s U (user password) value (Security handlers of revision 3 or greater) + + a) Create an encryption key based on the user password string, as described in "Algorithm 2: Computing an + encryption key". + b) Initialize the MD5 hash function and pass the 32-byte padding string shown in step (a) of "Algorithm 2: + Computing an encryption key" as input to this function. + c) Pass the first element of the file’s file identifier array (the value of the ID entry in the document’s trailer + dictionary; see Table 15) to the hash function and finish the hash. + d) Encrypt the 16-byte result of the hash, using an RC4 encryption function with the encryption key from step (a). + e) Do the following 19 times: Take the output from the previous invocation of the RC4 function and pass it as + input to a new invocation of the function; use an encryption key generated by taking each byte of the + original encryption key obtained in step (a) and performing an XOR (exclusive or) operation between that + byte and the single-byte value of the iteration counter (from 1 to 19). + f) Append 16 bytes of arbitrary padding to the output from the final invocation of the RC4 function and store + the 32-byte result as the value of the U entry in the encryption dictionary. """ - """ a) Create an encryption key based on the user password string, as described in "Algorithm 2: Computing an encryption key". """ - """ b) Initialize the MD5 hash function and pass the 32-byte padding string shown in step (a) of "Algorithm 2: - Computing an encryption key" as input to this function. """ u_hash = hashlib.md5(_PADDING) - """ c) Pass the first element of the file’s file identifier array (the value of the ID entry in the document’s trailer - dictionary; see Table 15) to the hash function and finish the hash. """ - u_hash.update(self.id1_entry) - """ d) Encrypt the 16-byte result of the hash, using an RC4 encryption function with the encryption key from step (a). """ - rc4_enc = CryptRC4(self.key).encrypt(u_hash.digest()) - """ e) Do the following 19 times: Take the output from the previous invocation of the RC4 function and pass it as - input to a new invocation of the function; use an encryption key generated by taking each byte of the - original encryption key obtained in step (a) and performing an XOR (exclusive or) operation between that - byte and the single-byte value of the iteration counter (from 1 to 19). - """ + u_hash.update(id1_entry) + rc4_enc = RC4_encrypt(key, u_hash.digest()) for i in range(1, 20): - key = bytes(bytearray([x ^ i for x in self.key])) - rc4_enc = CryptRC4(key).encrypt(rc4_enc) - """ f) Append 16 bytes of arbitrary padding to the output from the final invocation of the RC4 function and store - the 32-byte result as the value of the U entry in the encryption dictionary. - """ + rc4_key = bytes(bytearray([x ^ i for x in key])) + rc4_enc = RC4_encrypt(rc4_key, rc4_enc) return _padding(rc4_enc) - def _auth_user_password(self, u_entry: bytes, o_entry: bytes, user_pwd: bytes) -> bool: + @staticmethod + def verify_user_password(user_pwd: bytes, rev: int, key_size: int, o_entry: bytes, u_entry: bytes, + P: int, id1_entry: bytes, metadata_encrypted: bool) -> bytes: """ Algorithm 6: Authenticating the user password @@ -299,13 +342,18 @@ def _auth_user_password(self, u_entry: bytes, o_entry: bytes, user_pwd: bytes) - encryption dictionary’s U (user password) value (Security handlers of revision 3 or greater)") shall be used to decrypt the document. """ - u_value = self._compute_U_value(user_pwd, o_entry) - if self.R >= 3: + key = AlgR4.compute_key(user_pwd, rev, key_size, o_entry, P, id1_entry, metadata_encrypted) + u_value = AlgR4.compute_U_value(key, rev, id1_entry) + if rev >= 3: u_value = u_value[:16] u_entry = u_entry[:16] - return u_value == u_entry + if u_value != u_entry: + key = b"" + return key - def _auth_owner_password(self, u_entry: bytes, o_entry: bytes, owner_pwd: bytes=None) -> bool: + @staticmethod + def verify_owner_password(owner_pwd: bytes, rev: int, key_size: int, o_entry: bytes, u_entry: bytes, + P: int, id1_entry: bytes, metadata_encrypted: bool) -> bytes: """ Algorithm 7: Authenticating the owner password @@ -321,68 +369,176 @@ def _auth_owner_password(self, u_entry: bytes, o_entry: bytes, owner_pwd: bytes= c) The result of step (b) purports to be the user password. Authenticate this user password using "Algorithm 6: Authenticating the user password". If it is correct, the password supplied is the correct owner password. """ - if owner_pwd is None: - owner_pwd = b"" - a = _padding(owner_pwd) - o_hash_digest = hashlib.md5(a).digest() - if self.R >= 3: - for _ in range(50): - o_hash_digest = hashlib.md5(o_hash_digest).digest() - rc4_key = o_hash_digest[:self.Length // 8] + rc4_key = AlgR4.compute_O_value_key(owner_pwd, rev, key_size) - if self.R <= 2: - u_pwd = CryptRC4(rc4_key).decrypt(o_entry) + if rev <= 2: + u_pwd = RC4_decrypt(rc4_key, o_entry) else: u_pwd = o_entry for i in range(19, -1, -1): key = bytes(bytearray([x ^ i for x in rc4_key])) - u_pwd = CryptRC4(key).decrypt(u_pwd) - return self._auth_user_password(u_entry, o_entry, u_pwd) + u_pwd = RC4_decrypt(key, u_pwd) + return AlgR4.verify_user_password(u_pwd, rev, key_size, o_entry, u_entry, P, id1_entry, metadata_encrypted) -class CryptFilter: - def __init__(self, stmCrypt: CryptBase, strCrypt: CryptBase, efCrypt: CryptBase) -> None: - self.stmCrypt = stmCrypt - self.strCrypt = strCrypt - self.efCrypt = efCrypt +class AlgR5: + @staticmethod + def verify_owner_password(password: bytes, o_value: bytes, oe_value: bytes, u_value: bytes) -> bytes: + """ + Algorithm 3.2a Computing an encryption key + + To understand the algorithm below, it is necessary to treat the O and U strings in the Encrypt dictionary + as made up of three sections. The first 32 bytes are a hash value (explained below). The next 8 bytes are + called the Validation Salt. The final 8 bytes are called the Key Salt. + + 1. The password string is generated from Unicode input by processing the input string with the SASLprep + (IETF RFC 4013) profile of stringprep (IETF RFC 3454), and then converting to a UTF-8 representation. + 2. Truncate the UTF-8 representation to 127 bytes if it is longer than 127 bytes. + 3. Test the password against the owner key by computing the SHA-256 hash of the UTF-8 password + concatenated with the 8 bytes of owner Validation Salt, concatenated with the 48-byte U string. If the + 32-byte result matches the first 32 bytes of the O string, this is the owner password. + Compute an intermediate owner key by computing the SHA-256 hash of the UTF-8 password + concatenated with the 8 bytes of owner Key Salt, concatenated with the 48-byte U string. The 32-byte + result is the key used to decrypt the 32-byte OE string using AES-256 in CBC mode with no padding and + an initialization vector of zero. The 32-byte result is the file encryption key. + 4. Test the password against the user key by computing the SHA-256 hash of the UTF-8 password + concatenated with the 8 bytes of user Validation Salt. If the 32 byte result matches the first 32 bytes of + the U string, this is the user password. + Compute an intermediate user key by computing the SHA-256 hash of the UTF-8 password + concatenated with the 8 bytes of user Key Salt. The 32-byte result is the key used to decrypt the 32-byte + UE string using AES-256 in CBC mode with no padding and an initialization vector of zero. The 32-byte + result is the file encryption key. + 5. Decrypt the 16-byte Perms string using AES-256 in ECB mode with an initialization vector of zero and + the file encryption key as the key. Verify that bytes 9-11 of the result are the characters ‘a’, ‘d’, ‘b’. Bytes + 0-3 of the decrypted Perms entry, treated as a little-endian integer, are the user permissions. They + should match the value in the P key. + """ + password = password[:127] + if hashlib.sha256(password + o_value[32:40] + u_value).digest() != o_value[:32]: + return b"" + iv = bytes(0 for _ in range(16)) + tmp_key = hashlib.sha256(password + o_value[40:] + u_value).digest() + key = AES_CBC_decrypt(tmp_key, iv, oe_value) + return key - def encryptObject(self, obj: PdfObject) -> PdfObject: - # TODO - return NotImplemented + @staticmethod + def verify_user_password(password: bytes, u_value: bytes, ue_value: bytes) -> bytes: + """see :func:`verify_owner_password`""" + password = password[:127] + if hashlib.sha256(password + u_value[32:40]).digest() != u_value[:32]: + return b"" + iv = bytes(0 for _ in range(16)) + tmp_key = hashlib.sha256(password + u_value[40:]).digest() + return AES_CBC_decrypt(tmp_key, iv, ue_value) + + def verify_perms(key: bytes, perms: bytes, p: int, metadata_encrypted: bool) -> bytes: + """see :func:`verify_owner_password` and :func:`compute_Perms_value`""" + b8 = b'T' if metadata_encrypted else 'F' + p1 = struct.pack(" PdfObject: - if isinstance(obj, ByteStringObject) or isinstance(obj, TextStringObject): - data = self.strCrypt.decrypt(obj.original_bytes) - obj = createStringObject(data) - elif isinstance(obj, StreamObject): - obj._data = self.stmCrypt.decrypt(obj._data) - elif isinstance(obj, DictionaryObject): - for dictkey, value in list(obj.items()): - obj[dictkey] = self.decryptObject(value) - elif isinstance(obj, ArrayObject): - for i in range(len(obj)): - obj[i] = self.decryptObject(obj[i]) - return obj + @staticmethod + def generate_values(user_pwd: bytes, owner_pwd: bytes, key: bytes, p: int, metadata_encrypted: bool) -> dict: + u_value, ue_value = AlgR5.compute_U_value(user_pwd, key) + o_value, oe_value = AlgR5.compute_O_value(owner_pwd, key, u_value) + perms = AlgR5.compute_Perms_value(key, p, metadata_encrypted) + return { + "/U": u_value, + "/UE": ue_value, + "/O": o_value, + "/OE": oe_value, + "/Perms": perms, + } + + @staticmethod + def compute_U_value(password: bytes, key: bytes) -> typing.Tuple[bytes]: + """ + Algorithm 3.8 Computing the encryption dictionary’s U (user password) and UE (user encryption key) values + + 1. Generate 16 random bytes of data using a strong random number generator. The first 8 bytes are the + User Validation Salt. The second 8 bytes are the User Key Salt. Compute the 32-byte SHA-256 hash of + the password concatenated with the User Validation Salt. The 48-byte string consisting of the 32-byte + hash followed by the User Validation Salt followed by the User Key Salt is stored as the U key. + 2. Compute the 32-byte SHA-256 hash of the password concatenated with the User Key Salt. Using this + hash as the key, encrypt the file encryption key using AES-256 in CBC mode with no padding and an + initialization vector of zero. The resulting 32-byte string is stored as the UE key. + """ + random_bytes = bytes(random.randrange(0, 256) for _ in range(16)) + val_salt = random_bytes[:8] + key_salt = random_bytes[8:] + u_value = hashlib.sha256(password + val_salt).digest() + val_salt + key_salt + + tmp_key = hashlib.sha256(password + key_salt).digest() + iv = bytes(0 for _ in range(16)) + ue_value = AES_CBC_encrypt(tmp_key, iv, key) + return u_value, ue_value + + @staticmethod + def compute_O_value(password: bytes, key: bytes, u_value: bytes) -> typing.Tuple[bytes]: + """ + Algorithm 3.9 Computing the encryption dictionary’s O (owner password) and OE (owner encryption key) values + + 1. Generate 16 random bytes of data using a strong random number generator. The first 8 bytes are the + Owner Validation Salt. The second 8 bytes are the Owner Key Salt. Compute the 32-byte SHA-256 hash + of the password concatenated with the Owner Validation Salt and then concatenated with the 48-byte + U string as generated in Algorithm 3.8. The 48-byte string consisting of the 32-byte hash followed by + the Owner Validation Salt followed by the Owner Key Salt is stored as the O key. + 2. Compute the 32-byte SHA-256 hash of the password concatenated with the Owner Key Salt and then + concatenated with the 48-byte U string as generated in Algorithm 3.8. Using this hash as the key, + encrypt the file encryption key using AES-256 in CBC mode with no padding and an initialization vector + of zero. The resulting 32-byte string is stored as the OE key. + """ + random_bytes = bytes(random.randrange(0, 256) for _ in range(16)) + val_salt = random_bytes[:8] + key_salt = random_bytes[8:] + o_value = hashlib.sha256(password + val_salt + u_value).digest() + val_salt + key_salt + + tmp_key = hashlib.sha256(password + key_salt + u_value).digest() + iv = bytes(0 for _ in range(16)) + oe_value = AES_CBC_encrypt(tmp_key, iv, key) + return o_value, oe_value + + @staticmethod + def compute_Perms_value(key: bytes, p: int, metadata_encrypted: bool) -> bytes: + """ + Algorithm 3.10 Computing the encryption dictionary’s Perms (permissions) value + + 1. Extend the permissions (contents of the P integer) to 64 bits by setting the upper 32 bits to all 1’s. (This + allows for future extension without changing the format.) + 2. Record the 8 bytes of permission in the bytes 0-7 of the block, low order byte first. + 3. Set byte 8 to the ASCII value ' T ' or ' F ' according to the EncryptMetadata Boolean. + 4. Set bytes 9-11 to the ASCII characters ' a ', ' d ', ' b '. + 5. Set bytes 12-15 to 4 bytes of random data, which will be ignored. + 6. Encrypt the 16-byte block using AES-256 in ECB mode with an initialization vector of zero, using the file + encryption key as the key. The result (16 bytes) is stored as the Perms string, and checked for validity + when the file is opened. + """ + b8 = b'T' if metadata_encrypted else 'F' + rr = bytes(random.randrange(0, 256) for _ in range(4)) + data = struct.pack(" None: + def __init__(self, algV: int, entry: DictionaryObject, first_id_entry: bytes, StmF: str, StrF: str, EFF: str) -> None: self.algV = algV - self.handler = StandardSecurityHandler(rev, perm, keylen, metadata_encrypted, first_id_entry) + self.entry = entry + self.key_size = entry.get("/Length", 40) + self.id1_entry = first_id_entry self.StmF = StmF self.StrF = StrF self.EFF = EFF - def key(self) -> typing.Optional[bytes]: - return self.handler.key - - def encryptObject(self, obj: PdfObject) -> PdfObject: - # TODO - return NotImplemented + self._key = None + # keep key + self._user_keys = {} + self._owner_keys = {} def decryptObject(self, obj: PdfObject, idnum: int, generation: int) -> PdfObject: + """decrypt object""" + """ Algorithm 1: Encryption of data using the RC4 or AES algorithms @@ -404,44 +560,122 @@ def decryptObject(self, obj: PdfObject, idnum: int, generation: int) -> PdfObjec is used. The block size parameter is set to 16 bytes, and the initialization vector is a 16-byte random number that is stored as the first 16 bytes of the encrypted stream or string. """ + + """ + Algorithm 3.1a Encryption of data using the AES algorithm + 1. Use the 32-byte file encryption key for the AES-256 symmetric key algorithm, along with the string or + stream data to be encrypted. + Use the AES algorithm in Cipher Block Chaining (CBC) mode, which requires an initialization vector. The + block size parameter is set to 16 bytes, and the initialization vector is a 16-byte random number that is + stored as the first 16 bytes of the encrypted stream or string. + The output is the encrypted data to be stored in the PDF file. + """ pack1 = struct.pack(" CryptBase: + def _getCrypt(method: str, rc4_key: bytes, aes128_key: bytes, aes256_key: bytes) -> CryptBase: + if method == "/AESV3": + return CryptAES(aes256_key) if method == "/AESV2": - return CryptAES(aes_key) + return CryptAES(aes128_key) elif method == "/Identity": return CryptIdentity() else: return CryptRC4(rc4_key) - def encryptPdf(self, user_pwd: str, owner_pwd: str=None) -> DictionaryObject: - # TODO - return NotImplemented + def verify(self, user_pwd: str, owner_pwd: str) -> int: + key = self._user_keys.get(user_pwd) + if key: + self._key = key + return 1 + + key = self._owner_keys.get(owner_pwd) + if key: + self._key = key + return 2 - def decryptPdf(self, u_entry: bytes, o_entry: bytes, user_pwd: str, owner_pwd: str=None) -> int: - user_pwd = _bytes(user_pwd) - if owner_pwd is not None: - owner_pwd = _bytes(owner_pwd) - return self.handler.auth(u_entry, o_entry, user_pwd, owner_pwd) + rc = 0 + if self.algV <= 4: + key, rc = self.verify_r4(user_pwd, owner_pwd) + else: + key, rc = self.verify_r5(user_pwd, owner_pwd) + + if rc == 1: + self._key = key + self._user_keys[user_pwd] = key + elif rc == 2: + self._key = key + self._owner_keys[owner_pwd] = key + + return rc + + def verify_r4(self, user_pwd: str, owner_pwd: str) -> typing.Tuple[bytes, int]: + user_pwd1 = _bytes(user_pwd) + owner_pwd1 = _bytes(owner_pwd) + + R = self.entry["/R"] + P = self.entry["/P"] + P = (P + 0x100000000) % 0x100000000 # maybe < 0 + metadata_encrypted = self.entry.get("/EncryptMetadata", True) + o_entry = self.entry["/O"].getObject().original_bytes + u_entry = self.entry["/U"].getObject().original_bytes + + key = AlgR4.verify_user_password(user_pwd1, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) + if key: + return key, 1 + key = AlgR4.verify_owner_password(owner_pwd1, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) + if key: + return key, 2 + return b"", 0 + + def verify_r5(self, user_pwd: str, owner_pwd: str) -> typing.Tuple[bytes, int]: + # TODO: use SASLprep process + user_pwd1 = _bytes(user_pwd) + owner_pwd1 = _bytes(owner_pwd) + + o_entry = self.entry["/O"].getObject().original_bytes + u_entry = self.entry["/U"].getObject().original_bytes + oe_entry = self.entry["/OE"].getObject().original_bytes + ue_entry = self.entry["/UE"].getObject().original_bytes + + rc = 0 + key = AlgR5.verify_user_password(user_pwd1, u_entry, ue_entry) + if key: + rc = 1 + else: + key = AlgR5.verify_owner_password(owner_pwd1, o_entry, oe_entry, u_entry) + if key: + rc = 2 + if rc == 0: + return b"", 0 + # verify Perms + perms = self.entry["/Perms"].getObject().original_bytes + P = self.entry["/P"] + P = (P + 0x100000000) % 0x100000000 # maybe < 0 + metadata_encrypted = self.entry.get("/EncryptMetadata", True) + if not AlgR5.verify_perms(key, perms, P, metadata_encrypted): + return b"", 0 + return key, rc @staticmethod def read(encryption_entry: DictionaryObject, first_id_entry: bytes=None) -> "Encryption": @@ -456,9 +690,9 @@ def read(encryption_entry: DictionaryObject, first_id_entry: bytes=None) -> "Enc EFF = "/V2" V = encryption_entry.get("/V", 0) - if V not in (1, 2, 3, 4): + if V not in (1, 2, 3, 4, 5): raise NotImplementedError("Encryption V=%d NOT supported" % V) - if V == 4: + if V >= 4: filters = encryption_entry["/CF"] StmF = encryption_entry.get("/StmF", "/Identity") @@ -472,7 +706,7 @@ def read(encryption_entry: DictionaryObject, first_id_entry: bytes=None) -> "Enc if EFF != "/Identity": EFF = filters[EFF]["/CFM"] - allowed_methods = ("/Identity", "/V2", "/AESV2") + allowed_methods = ("/Identity", "/V2", "/AESV2", "/AESV3") if StmF not in allowed_methods: raise NotImplementedError("StmF Method %s NOT supported!" % StmF) if StrF not in allowed_methods: @@ -481,7 +715,7 @@ def read(encryption_entry: DictionaryObject, first_id_entry: bytes=None) -> "Enc raise NotImplementedError("EFF Method %s NOT supported!" % EFF) R = encryption_entry["/R"] - P = encryption_entry["/P"] - Length = encryption_entry.get("/Length", 5 * 8) - metadata_encrypted = encryption_entry.get("/EncryptMetadata", True) - return Encryption(V, R, P, Length, metadata_encrypted, first_id_entry, StmF, StrF, EFF) + if R > 5: + raise NotImplementedError("encryption R={} NOT supported!".format(R)) + + return Encryption(V, encryption_entry, first_id_entry, StmF, StrF, EFF) diff --git a/PyPDF2/pdf.py b/PyPDF2/pdf.py index 0a586d4cb..87f76809e 100644 --- a/PyPDF2/pdf.py +++ b/PyPDF2/pdf.py @@ -2074,19 +2074,14 @@ def decrypt(self, password): self._override_encryption = False def _decrypt(self, password): - # already got the KEY - if hasattr(self, "_encryption"): - return 3 from PyPDF2.encryption import Encryption id_entry = self.trailer.get("/ID") - id1_entry = id_entry[0].getObject().original_bytes if id_entry else None + id1_entry = id_entry[0].getObject().original_bytes if id_entry else b"" encryptEntry = self.trailer['/Encrypt'].getObject() encryption = Encryption.read(encryptEntry, id1_entry) - u_entry = encryptEntry["/U"].getObject().original_bytes - o_entry = encryptEntry["/O"].getObject().original_bytes # maybe password is owner password # TODO: add/modify api to set owner password - rr = encryption.decryptPdf(u_entry, o_entry, password, password) + rr = encryption.verify(password, password) if rr > 0: self._encryption = encryption return rr diff --git a/Resources/encryption/enc7.pdf b/Resources/encryption/enc7.pdf index 406b6ed8508224fc6347a21d75a77f50177b5ea3..07a973997233a2d75fcbf38b1d6230df081ce9d2 100644 GIT binary patch delta 14652 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 delta 14652 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 diff --git a/Resources/encryption/enc9.pdf b/Resources/encryption/enc9.pdf index 3b5bde23dc4ceac77ea95301fb6bcb7cfa8067e9..80f4a61d67ccabd6e0d02c02159e161f9d9ec922 100644 GIT binary patch delta 14651 zcmYM51yEF9*zlz#C8S$GN@P2f7DO79P(WZ)K)QSB?gjx#N$HS~4rwKn5J3c_1VK8# z{eSPg^UluPowN6zC(rYoJNNFdFOZ}!kR)E81e{>-nt(%r(Lgv71;l{ySTqcdLqib| z1PTQJVNrMx3G#r9M!68sI8X+ej{m9t0y zQ6M}31Oj6~KqLYJL}CAv<%C1ISlQbtqg-$TGB_*>3`N7Sa0DEOg&^Q~JP<}ep%54( z8h|2thl3yxKoAmw2Ox074*&&3;~-cF9Ed^?wGe%R0I+Bbj_3&pgomN=a3lo0cLcur?0szJ$u^>1a03m>Y5I7hK z!XiOvB$k*4C^3LoJO=ZhFb$liyS)>Z7+5F-bJPraO<`Dox1JHOhQJ9uJ_J6{F1fbv`AO;5l6R#)WK_Da= zfd-?{Ks=I|C*lZAJOu&apcpg~gN7k+7$BaQ0pb{ggx~-OI0yzKnu$liu}CqIKp+qd!lPj*01l5rATSUl3IHLx1%yJ0>k@{BpzsI)27o|Ah%o{Hi0+Q=gyD(V2SWeT>58_-VO#`cki=CCKoQdg!-Ak#qI?Jngd$o7z{0R# z9C6t}z<3xQ0|Nh7HgE(K1w|sjKqLf!L_+}xz<;vztz2w~>kkiwOA@5He~esBlBebMR66E;_7ooY5!iHOTXgIB zuO0!Z zwtmVi`tfIC6J_&AbRXyAHJ9%&X7ly;-?ez%Mv4;bg)OB1EPuMjIW-)}^GZ*%XK=GP z(J36})KODekPsKo^Q;ozo)1wh$EhF*t(sIq&?m3j@#4X;B`3+D`6oh#RR% zL*205V$nF*y#N8%KzcRMDxPt~2wZin^;TWPmTDhdO%rzL9olRPnG@Rjg#-l@PHWP` zw`Wv2=^J(4-M)TF2xFrNP&-FcfG^T6;w*;kmn*X6CyK-k`=;LZT9lj{wpzjhe=}=^ z2cxm9A$mUmrWfx;6A2&DdJ=!0@Kh`s;AlKxHr7(5@u~4kb7?>EW=qd$6AfORJfu)v zE?b?FyL@_SW%*l2;Cj<;glch6MkPwL#^6p<`gLx?O#EDGr;F^>cMTr+L^1<21#Xel^{H2(&911Da;vbSSGS^Vb$FJm+~8OVKPngSyD5NH~|j@;L&gd5)8#7 zfG8vw03@~q1QbbZOlT~zZ$kh8ED8k&0>EGh42Z;mfdD+QV1dMXAZ{FZV!1rUy|Qw4 zaUyO3AS41r+#rZ835G;qi8HXo)(!;`dkV4Mp%5r>H^G8|C=dn=2V&tsVqv4`AXp5s zN8^CR1_e#BrA<{p5jzu@*n)}O6^+1x5lG@ySR52h+&h41Fd7E=uf74qBLaaZ)+`PJ z!w`!P10psO;vR#7)IFkOAt8{}&8Sv4W!22idN3CGt3-HbPE0b8?vyoe8za6`Q5Yq- znUP!xJ#=5+SQrcEcohwl5U!PH7U1)oLOnvhX``Zgdan9~1HAs_wzB~Z)vwAtiHLQ5 zbVod+z|u*NNJqAouy}mP+ptYLM&7q&uit0MsUMJ1JT0Z7N%E2SZ_kE}&v_uPVynC!)#!g> zkK*=O;=j7qmhf31oj*Ih|Ib`ZK3g>EASW@d%i~P5fs}v$XT#xKU>G$)41e%LnBlBx zr!_s3^+H(V(%8n~4vw1OODfeVzBZ@b{lqY^;D^S|zrl|Ok5XQ1W!6@koY|-Dj9g9Y zC`OL6l-OjPK3>eF^LFT0dQrnoCIpHsTkq5LWMod`f6BallKRq&v3=^#4!_g}XFhf% zkW5oTqR~pL+wx`)Ul`M #5UY1~0Sn6}Xvd4K597S2~0!I;T1aaF8Eewg_)- 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 delta 14651 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 diff --git a/Tests/test_encryption.py b/Tests/test_encryption.py index 8e3586546..fc756d418 100644 --- a/Tests/test_encryption.py +++ b/Tests/test_encryption.py @@ -28,13 +28,13 @@ # created by `qpdf --encrypt "asdfzxcv" "" 128 --use-aes=y -- enc0.pdf enc6.pdf` (os.path.join(RESOURCE_ROOT, "encryption", "enc6.pdf")), - # # V=5 and AES256 (TODO) - # # created by `qpdf --encrypt "" "" 256 -- enc0.pdf enc7.pdf` - # (os.path.join(RESOURCE_ROOT, "encryption", "enc7.pdf")), - # # created by `qpdf --encrypt "asdfzxcv" "" 256 -- enc0.pdf enc8.pdf` - # (os.path.join(RESOURCE_ROOT, "encryption", "enc8.pdf")), - # # created by `qpdf --encrypt "" "asdfzxcv" 256 -- enc0.pdf enc9.pdf` - # (os.path.join(RESOURCE_ROOT, "encryption", "enc9.pdf")), + # # V=5 and R=5 use AES-256 + # # created by `qpdf --encrypt "" "" 256 --force-R5 -- enc0.pdf enc7.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc7.pdf")), + # # created by `qpdf --encrypt "asdfzxcv" "" 256 --force-R5 -- enc0.pdf enc8.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc8.pdf")), + # # created by `qpdf --encrypt "" "asdfzxcv" 256 --force-R5 -- enc0.pdf enc9.pdf` + (os.path.join(RESOURCE_ROOT, "encryption", "enc9.pdf")), # asdfzxcv is owner password # created by `qpdf --encrypt "" "asdfzxcv" 128 --use-aes=y -- enc0.pdf enca.pdf` From 84532bb782a253d13ba72ca75d4f81dd64c6cc50 Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Thu, 21 Apr 2022 11:10:43 +0800 Subject: [PATCH 07/13] remove AES code for easier maintaining --- PyPDF2/_aes.py | 827 ------------------------------------------- PyPDF2/encryption.py | 25 +- PyPDF2/errors.py | 3 + PyPDF2/pdf.py | 5 +- requirements/ci.in | 3 +- requirements/ci.txt | 13 +- tox.ini | 1 + 7 files changed, 22 insertions(+), 855 deletions(-) delete mode 100644 PyPDF2/_aes.py diff --git a/PyPDF2/_aes.py b/PyPDF2/_aes.py deleted file mode 100644 index 0f78aea21..000000000 --- a/PyPDF2/_aes.py +++ /dev/null @@ -1,827 +0,0 @@ -# coding: utf-8 -# -# Copyright (c) 2022, 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. - -""" -based on rijndael-alg-fst.c -""" - -import struct -import typing - - -_TE0 = ( - 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, - 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, - 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, - 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, - 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, - 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, - 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, - 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, - 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, - 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, - 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, - 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, - 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, - 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, - 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, - 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, - 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, - 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, - 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, - 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, - 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, - 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, - 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, - 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, - 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, - 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, - 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, - 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, - 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, - 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, - 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, - 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, -) -_TE1 = ( - 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, - 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, - 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, - 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, - 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, - 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, - 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, - 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, - 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, - 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, - 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, - 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, - 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, - 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, - 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, - 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, - 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, - 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, - 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, - 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, - 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, - 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, - 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, - 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, - 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, - 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, - 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, - 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, - 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, - 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, - 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, - 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, -) -_TE2 = ( - 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, - 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, - 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, - 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, - 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, - 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, - 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, - 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, - 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, - 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, - 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, - 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, - 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, - 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, - 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, - 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, - 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, - 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, - 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, - 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, - 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, - 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, - 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, - 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, - 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, - 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, - 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, - 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, - 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, - 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, - 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, - 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, -) -_TE3 = ( - 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, - 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, - 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, - 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, - 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, - 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, - 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, - 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, - 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, - 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, - 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, - 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, - 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, - 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, - 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, - 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, - 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, - 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, - 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, - 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, - 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, - 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, - 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, - 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, - 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, - 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, - 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, - 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, - 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, - 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, - 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, - 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, -) -_TE4 = ( - 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, - 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, - 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, - 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, - 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, - 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515, - 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, - 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, - 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, - 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, - 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, - 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, - 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, - 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8, - 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, - 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, - 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, - 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, - 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, - 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, - 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, - 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979, - 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, - 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, - 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, - 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, - 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, - 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, - 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, - 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf, - 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, - 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616, -) -_TD0 = ( - 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, - 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, - 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, - 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, - 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, - 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, - 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, - 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, - 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, - 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, - 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, - 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, - 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, - 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, - 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, - 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, - 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, - 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, - 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, - 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, - 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, - 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, - 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, - 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, - 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, - 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, - 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, - 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, - 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, - 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, - 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, - 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, -) -_TD1 = ( - 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, - 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, - 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, - 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, - 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, - 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, - 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, - 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, - 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, - 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, - 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, - 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, - 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, - 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, - 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, - 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, - 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, - 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, - 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, - 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, - 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, - 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, - 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, - 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, - 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, - 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, - 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, - 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, - 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, - 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, - 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, - 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, -) -_TD2 = ( - 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, - 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, - 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, - 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, - 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, - 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, - 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, - 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, - 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, - 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, - 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, - 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, - 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, - 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, - 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, - 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, - 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, - 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, - 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, - 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, - 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, - 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, - 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, - 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, - 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, - 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, - 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, - 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, - 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, - 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, - 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, - 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, -) -_TD3 = ( - 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, - 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, - 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, - 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, - 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, - 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, - 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, - 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, - 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, - 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, - 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, - 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, - 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, - 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, - 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, - 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, - 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, - 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, - 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, - 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, - 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, - 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, - 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, - 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, - 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, - 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, - 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, - 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, - 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, - 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, - 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, - 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, -) -_TD4 = ( - 0x52525252, 0x09090909, 0x6a6a6a6a, 0xd5d5d5d5, 0x30303030, 0x36363636, 0xa5a5a5a5, 0x38383838, - 0xbfbfbfbf, 0x40404040, 0xa3a3a3a3, 0x9e9e9e9e, 0x81818181, 0xf3f3f3f3, 0xd7d7d7d7, 0xfbfbfbfb, - 0x7c7c7c7c, 0xe3e3e3e3, 0x39393939, 0x82828282, 0x9b9b9b9b, 0x2f2f2f2f, 0xffffffff, 0x87878787, - 0x34343434, 0x8e8e8e8e, 0x43434343, 0x44444444, 0xc4c4c4c4, 0xdededede, 0xe9e9e9e9, 0xcbcbcbcb, - 0x54545454, 0x7b7b7b7b, 0x94949494, 0x32323232, 0xa6a6a6a6, 0xc2c2c2c2, 0x23232323, 0x3d3d3d3d, - 0xeeeeeeee, 0x4c4c4c4c, 0x95959595, 0x0b0b0b0b, 0x42424242, 0xfafafafa, 0xc3c3c3c3, 0x4e4e4e4e, - 0x08080808, 0x2e2e2e2e, 0xa1a1a1a1, 0x66666666, 0x28282828, 0xd9d9d9d9, 0x24242424, 0xb2b2b2b2, - 0x76767676, 0x5b5b5b5b, 0xa2a2a2a2, 0x49494949, 0x6d6d6d6d, 0x8b8b8b8b, 0xd1d1d1d1, 0x25252525, - 0x72727272, 0xf8f8f8f8, 0xf6f6f6f6, 0x64646464, 0x86868686, 0x68686868, 0x98989898, 0x16161616, - 0xd4d4d4d4, 0xa4a4a4a4, 0x5c5c5c5c, 0xcccccccc, 0x5d5d5d5d, 0x65656565, 0xb6b6b6b6, 0x92929292, - 0x6c6c6c6c, 0x70707070, 0x48484848, 0x50505050, 0xfdfdfdfd, 0xedededed, 0xb9b9b9b9, 0xdadadada, - 0x5e5e5e5e, 0x15151515, 0x46464646, 0x57575757, 0xa7a7a7a7, 0x8d8d8d8d, 0x9d9d9d9d, 0x84848484, - 0x90909090, 0xd8d8d8d8, 0xabababab, 0x00000000, 0x8c8c8c8c, 0xbcbcbcbc, 0xd3d3d3d3, 0x0a0a0a0a, - 0xf7f7f7f7, 0xe4e4e4e4, 0x58585858, 0x05050505, 0xb8b8b8b8, 0xb3b3b3b3, 0x45454545, 0x06060606, - 0xd0d0d0d0, 0x2c2c2c2c, 0x1e1e1e1e, 0x8f8f8f8f, 0xcacacaca, 0x3f3f3f3f, 0x0f0f0f0f, 0x02020202, - 0xc1c1c1c1, 0xafafafaf, 0xbdbdbdbd, 0x03030303, 0x01010101, 0x13131313, 0x8a8a8a8a, 0x6b6b6b6b, - 0x3a3a3a3a, 0x91919191, 0x11111111, 0x41414141, 0x4f4f4f4f, 0x67676767, 0xdcdcdcdc, 0xeaeaeaea, - 0x97979797, 0xf2f2f2f2, 0xcfcfcfcf, 0xcececece, 0xf0f0f0f0, 0xb4b4b4b4, 0xe6e6e6e6, 0x73737373, - 0x96969696, 0xacacacac, 0x74747474, 0x22222222, 0xe7e7e7e7, 0xadadadad, 0x35353535, 0x85858585, - 0xe2e2e2e2, 0xf9f9f9f9, 0x37373737, 0xe8e8e8e8, 0x1c1c1c1c, 0x75757575, 0xdfdfdfdf, 0x6e6e6e6e, - 0x47474747, 0xf1f1f1f1, 0x1a1a1a1a, 0x71717171, 0x1d1d1d1d, 0x29292929, 0xc5c5c5c5, 0x89898989, - 0x6f6f6f6f, 0xb7b7b7b7, 0x62626262, 0x0e0e0e0e, 0xaaaaaaaa, 0x18181818, 0xbebebebe, 0x1b1b1b1b, - 0xfcfcfcfc, 0x56565656, 0x3e3e3e3e, 0x4b4b4b4b, 0xc6c6c6c6, 0xd2d2d2d2, 0x79797979, 0x20202020, - 0x9a9a9a9a, 0xdbdbdbdb, 0xc0c0c0c0, 0xfefefefe, 0x78787878, 0xcdcdcdcd, 0x5a5a5a5a, 0xf4f4f4f4, - 0x1f1f1f1f, 0xdddddddd, 0xa8a8a8a8, 0x33333333, 0x88888888, 0x07070707, 0xc7c7c7c7, 0x31313131, - 0xb1b1b1b1, 0x12121212, 0x10101010, 0x59595959, 0x27272727, 0x80808080, 0xecececec, 0x5f5f5f5f, - 0x60606060, 0x51515151, 0x7f7f7f7f, 0xa9a9a9a9, 0x19191919, 0xb5b5b5b5, 0x4a4a4a4a, 0x0d0d0d0d, - 0x2d2d2d2d, 0xe5e5e5e5, 0x7a7a7a7a, 0x9f9f9f9f, 0x93939393, 0xc9c9c9c9, 0x9c9c9c9c, 0xefefefef, - 0xa0a0a0a0, 0xe0e0e0e0, 0x3b3b3b3b, 0x4d4d4d4d, 0xaeaeaeae, 0x2a2a2a2a, 0xf5f5f5f5, 0xb0b0b0b0, - 0xc8c8c8c8, 0xebebebeb, 0xbbbbbbbb, 0x3c3c3c3c, 0x83838383, 0x53535353, 0x99999999, 0x61616161, - 0x17171717, 0x2b2b2b2b, 0x04040404, 0x7e7e7e7e, 0xbabababa, 0x77777777, 0xd6d6d6d6, 0x26262626, - 0xe1e1e1e1, 0x69696969, 0x14141414, 0x63636363, 0x55555555, 0x21212121, 0x0c0c0c0c, 0x7d7d7d7d, -) - -_RCON = ( - 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, # for 128-bit blocks, Rijndael never uses more than 10 rcon values -) - - -def _rijndaelKeySetupEnc(key: bytes) -> typing.Tuple[int]: - """Expand the cipher key into the encryption key schedule.""" - keylen = len(key) - if keylen == 16: - rc = 10 - rk = [0] * (rc + 1) * 4 - rk[:4] = struct.unpack(">IIII", key) - for i in range(0, len(rk) - 4, 4): - temp = rk[i + 3] - rk[i + 4] = rk[i + 0] \ - ^ (_TE4[(temp >> 16) & 0xff] & 0xff000000) \ - ^ (_TE4[(temp >> 8) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(temp ) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(temp >> 24) ] & 0x000000ff) \ - ^_RCON[i // 4] - rk[i + 5] = rk[i + 1] ^ rk[i + 4] - rk[i + 6] = rk[i + 2] ^ rk[i + 5] - rk[i + 7] = rk[i + 3] ^ rk[i + 6] - elif keylen == 24: - rc = 12 - rk = [0] * (rc + 1) * 4 - rk[:6] = struct.unpack(">IIIIII", key) - for i in range(0, len(rk) - 6, 6): - temp = rk[i + 5] - rk[i + 6] = rk[i + 0] \ - ^ (_TE4[(temp >> 16) & 0xff] & 0xff000000) \ - ^ (_TE4[(temp >> 8) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(temp ) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(temp >> 24) ] & 0x000000ff) \ - ^_RCON[i // 6] - rk[i + 7] = rk[i + 1] ^ rk[i + 6] - rk[i + 8] = rk[i + 2] ^ rk[i + 7] - rk[i + 9] = rk[i + 3] ^ rk[i + 8] - if i // 6 == 7: - break - rk[i + 10] = rk[i + 4] ^ rk[i + 9] - rk[i + 11] = rk[i + 5] ^ rk[i + 10] - elif keylen == 32: - rc = 14 - rk = [0] * (rc + 1) * 4 - rk[:8] = struct.unpack(">IIIIIIII", key) - for i in range(0, len(rk) - 8, 8): - temp = rk[i + 7] - rk[i + 8] = rk[i + 0] \ - ^ (_TE4[(temp >> 16) & 0xff] & 0xff000000) \ - ^ (_TE4[(temp >> 8) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(temp ) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(temp >> 24) ] & 0x000000ff) \ - ^_RCON[i // 8] - rk[i + 9] = rk[i + 1] ^ rk[i + 8] - rk[i + 10] = rk[i + 2] ^ rk[i + 9] - rk[i + 11] = rk[i + 3] ^ rk[i + 10] - if i // 8 == 6: - break - temp = rk[i + 11] - rk[i + 12] = rk[i + 4] \ - ^ (_TE4[(temp >> 24) ] & 0xff000000) \ - ^ (_TE4[(temp >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(temp >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(temp ) & 0xff] & 0x000000ff) - rk[i + 13] = rk[i + 5] ^ rk[i + 12] - rk[i + 14] = rk[i + 6] ^ rk[i + 13] - rk[i + 15] = rk[i + 7] ^ rk[i + 14] - else: - raise ValueError("invalid key size: {}, must be one of (128, 192, 256)!".format(keylen * 8)) - - return tuple(rk) - - -def _rijndaelKeySetupDec(rk: typing.Tuple[int]) -> typing.Tuple[int]: - """Expand the cipher key into the decryption key schedule.""" - # expand the cipher key: - rk = list(rk) - # invert the order of the round keys: - xl = len(rk) - i, j = 0, xl - 4 - while i < j: - temp = rk[i:i + 4] - rk[i:i + 4] = rk[j:j + 4] - rk[j:j + 4] = temp - i += 4 - j -= 4 - # apply the inverse MixColumn transform to all round keys but the first and the last: - for i in range(4, xl - 4, 4): - rk[i + 0] = \ - _TD0[_TE4[(rk[i + 0] >> 24)] & 0xff] \ - ^ _TD1[_TE4[(rk[i + 0] >> 16) & 0xff] & 0xff] \ - ^ _TD2[_TE4[(rk[i + 0] >> 8) & 0xff] & 0xff] \ - ^ _TD3[_TE4[(rk[i + 0] ) & 0xff] & 0xff] - rk[i + 1] = \ - _TD0[_TE4[(rk[i + 1] >> 24)] & 0xff] \ - ^ _TD1[_TE4[(rk[i + 1] >> 16) & 0xff] & 0xff] \ - ^ _TD2[_TE4[(rk[i + 1] >> 8) & 0xff] & 0xff] \ - ^ _TD3[_TE4[(rk[i + 1] ) & 0xff] & 0xff] - rk[i + 2] = \ - _TD0[_TE4[(rk[i + 2] >> 24)] & 0xff] \ - ^ _TD1[_TE4[(rk[i + 2] >> 16) & 0xff] & 0xff] \ - ^ _TD2[_TE4[(rk[i + 2] >> 8) & 0xff] & 0xff] \ - ^ _TD3[_TE4[(rk[i + 2] ) & 0xff] & 0xff] - rk[i + 3] = \ - _TD0[_TE4[(rk[i + 3] >> 24)] & 0xff] \ - ^ _TD1[_TE4[(rk[i + 3] >> 16) & 0xff] & 0xff] \ - ^ _TD2[_TE4[(rk[i + 3] >> 8) & 0xff] & 0xff] \ - ^ _TD3[_TE4[(rk[i + 3] ) & 0xff] & 0xff] - return tuple(rk) - - -def _rijndaelEncrypt(rk: typing.Tuple[int], text: bytes): - rc = len(rk) // 4 - 1 # round - - # map byte array block to cipher state and add initial round key: - ss = struct.unpack(">IIII", text) - s0 = ss[0] ^ rk[0] - s1 = ss[1] ^ rk[1] - s2 = ss[2] ^ rk[2] - s3 = ss[3] ^ rk[3] - - # round 1: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[ 4] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[ 5] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[ 6] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[ 7] - # round 2: - s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[ 8] - s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[ 9] - s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[10] - s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[11] - # round 3: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[12] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[13] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[14] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[15] - # round 4: - s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[16] - s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[17] - s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[18] - s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[19] - # round 5: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[20] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[21] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[22] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[23] - # round 6: - s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[24] - s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[25] - s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[26] - s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[27] - # round 7: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[28] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[29] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[30] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[31] - # round 8: - s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[32] - s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[33] - s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[34] - s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[35] - # round 9: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[36] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[37] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[38] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[39] - if rc > 10: - # round 10: - s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[40] - s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[41] - s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[42] - s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[43] - # round 11: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[44] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[45] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[46] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[47] - if rc > 12: - # round 12: - s0 = _TE0[t0 >> 24] ^ _TE1[(t1 >> 16) & 0xff] ^ _TE2[(t2 >> 8) & 0xff] ^ _TE3[t3 & 0xff] ^ rk[48] - s1 = _TE0[t1 >> 24] ^ _TE1[(t2 >> 16) & 0xff] ^ _TE2[(t3 >> 8) & 0xff] ^ _TE3[t0 & 0xff] ^ rk[49] - s2 = _TE0[t2 >> 24] ^ _TE1[(t3 >> 16) & 0xff] ^ _TE2[(t0 >> 8) & 0xff] ^ _TE3[t1 & 0xff] ^ rk[50] - s3 = _TE0[t3 >> 24] ^ _TE1[(t0 >> 16) & 0xff] ^ _TE2[(t1 >> 8) & 0xff] ^ _TE3[t2 & 0xff] ^ rk[51] - # round 13: - t0 = _TE0[s0 >> 24] ^ _TE1[(s1 >> 16) & 0xff] ^ _TE2[(s2 >> 8) & 0xff] ^ _TE3[s3 & 0xff] ^ rk[52] - t1 = _TE0[s1 >> 24] ^ _TE1[(s2 >> 16) & 0xff] ^ _TE2[(s3 >> 8) & 0xff] ^ _TE3[s0 & 0xff] ^ rk[53] - t2 = _TE0[s2 >> 24] ^ _TE1[(s3 >> 16) & 0xff] ^ _TE2[(s0 >> 8) & 0xff] ^ _TE3[s1 & 0xff] ^ rk[54] - t3 = _TE0[s3 >> 24] ^ _TE1[(s0 >> 16) & 0xff] ^ _TE2[(s1 >> 8) & 0xff] ^ _TE3[s2 & 0xff] ^ rk[55] - - # apply last round and map cipher state to byte array block: - s0 = rk[-4] \ - ^ (_TE4[(t0 >> 24) ] & 0xff000000) \ - ^ (_TE4[(t1 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(t2 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(t3 ) & 0xff] & 0x000000ff) - s1 = rk[-3] \ - ^ (_TE4[(t1 >> 24) ] & 0xff000000) \ - ^ (_TE4[(t2 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(t3 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(t0 ) & 0xff] & 0x000000ff) - s2 = rk[-2] \ - ^ (_TE4[(t2 >> 24) ] & 0xff000000) \ - ^ (_TE4[(t3 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(t0 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(t1 ) & 0xff] & 0x000000ff) - s3 = rk[-1] \ - ^ (_TE4[(t3 >> 24) ] & 0xff000000) \ - ^ (_TE4[(t0 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TE4[(t1 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TE4[(t2 ) & 0xff] & 0x000000ff) - - return struct.pack(">IIII", s0, s1, s2, s3) - - -def _rijndaelDecrypt(rk: typing.Tuple[int], data: bytes) -> bytes: - rc = len(rk) // 4 - 1 # round - - # map byte array block to cipher state and add initial round key: - ss = struct.unpack(">IIII", data) - s0 = ss[0] ^ rk[0] - s1 = ss[1] ^ rk[1] - s2 = ss[2] ^ rk[2] - s3 = ss[3] ^ rk[3] - - # round 1: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[ 4] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[ 5] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[ 6] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[ 7] - # round 2: - s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[ 8] - s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[ 9] - s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[10] - s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[11] - # round 3: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[12] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[13] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[14] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[15] - # round 4: - s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[16] - s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[17] - s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[18] - s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[19] - # round 5: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[20] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[21] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[22] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[23] - # round 6: - s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[24] - s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[25] - s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[26] - s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[27] - # round 7: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[28] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[29] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[30] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[31] - # round 8: - s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[32] - s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[33] - s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[34] - s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[35] - # round 9: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[36] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[37] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[38] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[39] - if rc > 10: - # round 10: - s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[40] - s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[41] - s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[42] - s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[43] - # round 11: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[44] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[45] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[46] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[47] - if rc > 12: - # round 12: - s0 = _TD0[t0 >> 24] ^ _TD1[(t3 >> 16) & 0xff] ^ _TD2[(t2 >> 8) & 0xff] ^ _TD3[t1 & 0xff] ^ rk[48] - s1 = _TD0[t1 >> 24] ^ _TD1[(t0 >> 16) & 0xff] ^ _TD2[(t3 >> 8) & 0xff] ^ _TD3[t2 & 0xff] ^ rk[49] - s2 = _TD0[t2 >> 24] ^ _TD1[(t1 >> 16) & 0xff] ^ _TD2[(t0 >> 8) & 0xff] ^ _TD3[t3 & 0xff] ^ rk[50] - s3 = _TD0[t3 >> 24] ^ _TD1[(t2 >> 16) & 0xff] ^ _TD2[(t1 >> 8) & 0xff] ^ _TD3[t0 & 0xff] ^ rk[51] - # round 13: - t0 = _TD0[s0 >> 24] ^ _TD1[(s3 >> 16) & 0xff] ^ _TD2[(s2 >> 8) & 0xff] ^ _TD3[s1 & 0xff] ^ rk[52] - t1 = _TD0[s1 >> 24] ^ _TD1[(s0 >> 16) & 0xff] ^ _TD2[(s3 >> 8) & 0xff] ^ _TD3[s2 & 0xff] ^ rk[53] - t2 = _TD0[s2 >> 24] ^ _TD1[(s1 >> 16) & 0xff] ^ _TD2[(s0 >> 8) & 0xff] ^ _TD3[s3 & 0xff] ^ rk[54] - t3 = _TD0[s3 >> 24] ^ _TD1[(s2 >> 16) & 0xff] ^ _TD2[(s1 >> 8) & 0xff] ^ _TD3[s0 & 0xff] ^ rk[55] - - # apply last round and map cipher state to byte array block: - s0 = rk[-4] \ - ^ (_TD4[(t0 >> 24) ] & 0xff000000) \ - ^ (_TD4[(t3 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TD4[(t2 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TD4[(t1 ) & 0xff] & 0x000000ff) - s1 = rk[-3] \ - ^ (_TD4[(t1 >> 24) ] & 0xff000000) \ - ^ (_TD4[(t0 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TD4[(t3 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TD4[(t2 ) & 0xff] & 0x000000ff) - s2 = rk[-2] \ - ^ (_TD4[(t2 >> 24) ] & 0xff000000) \ - ^ (_TD4[(t1 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TD4[(t0 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TD4[(t3 ) & 0xff] & 0x000000ff) - s3 = rk[-1] \ - ^ (_TD4[(t3 >> 24) ] & 0xff000000) \ - ^ (_TD4[(t2 >> 16) & 0xff] & 0x00ff0000) \ - ^ (_TD4[(t1 >> 8) & 0xff] & 0x0000ff00) \ - ^ (_TD4[(t0 ) & 0xff] & 0x000000ff) - - return struct.pack(">IIII", s0, s1, s2, s3) - - -class AESECB: - def __init__(self, key: bytes) -> None: - self._ek = _rijndaelKeySetupEnc(key) - self._dk = _rijndaelKeySetupDec(self._ek) - - def encrypt(self, data: bytes) -> bytes: - ee = [] - for i in range(0, len(data), 16): - ee.append(_rijndaelEncrypt(self._ek, data[i:i + 16])) - return b"".join(ee) - - def decrypt(self, data: bytes) -> bytes: - dd = [] - for i in range(0, len(data), 16): - dd.append(_rijndaelDecrypt(self._dk, data[i:i + 16])) - return b"".join(dd) - - -class AESCBC: - def __init__(self, key: bytes) -> None: - self._ek = _rijndaelKeySetupEnc(key) - self._dk = _rijndaelKeySetupDec(self._ek) - - def encrypt(self, iv: bytes, data: bytes) -> bytes: - cc = bytes(iv) # in case bytearray - ee = b"" - xl = len(data) - for i in range(0, xl, 16): - dd = bytes(bytearray(cc[j] ^ data[i + j] for j in range(16))) - cc = _rijndaelEncrypt(self._ek, dd) - ee += cc - return ee - - def decrypt(self, iv: bytes, data: bytes) -> bytes: - cc = bytes(iv) # in case bytearray - dd = b"" - xl = len(data) - for i in range(0, xl, 16): - xx = _rijndaelDecrypt(self._dk, data[i:i + 16]) - dd += bytes(bytearray(cc[j] ^ xx[j] for j in range(16))) - cc = data[i:i + 16] - return dd - - -def _test(): - key128 = b"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c" - rk_128 = ( - 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c, 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605, - 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f, 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b, - 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00, 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc, - 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd, 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f, - 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f, 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e, - 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6, - ) - assert rk_128 == _rijndaelKeySetupEnc(key128) - - key192 = b"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b" - rk_192 = ( - 0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5, 0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5, - 0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2, 0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd, - 0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f, 0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6, - 0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767, 0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971, - 0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3, 0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e, - 0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753, 0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5, - 0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202, - ) - assert rk_192 == _rijndaelKeySetupEnc(key192) - - key256 = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4" - rk_256 = ( - 0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781, 0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4, - 0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde, 0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a, - 0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96, 0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3, - 0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464, 0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214, - 0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80, 0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239, - 0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15, 0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3, - 0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a, 0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d, - 0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e, - ) - assert rk_256 == _rijndaelKeySetupEnc(key256) - - # test for encrypt / decrypt - import random - from Crypto.Cipher import AES as PyCryptoAES - - def _test_enc_dec(aes0, aes1, pp): - e0 = aes0.encrypt(pp) - d0 = aes0.decrypt(e0) - - e1 = aes1.encrypt(pp) - d1 = aes1.decrypt(e1) - - assert pp == d0 == d1 - assert e0 == e1 - - aes128_0 = AESECB(key128) - aes192_0 = AESECB(key192) - aes256_0 = AESECB(key256) - - aes128_1 = PyCryptoAES.new(key128, PyCryptoAES.MODE_ECB) - aes192_1 = PyCryptoAES.new(key192, PyCryptoAES.MODE_ECB) - aes256_1 = PyCryptoAES.new(key256, PyCryptoAES.MODE_ECB) - - for _ in range(10): - pp = bytes(bytearray(random.randint(0, 255) for _ in range(32))) - _test_enc_dec(aes128_0, aes128_1, pp) - _test_enc_dec(aes192_0, aes192_1, pp) - _test_enc_dec(aes256_0, aes256_1, pp) - - def _test_CBC(key, iv, pp): - aes0 = AESCBC(key) - e0 = aes0.encrypt(iv, pp) - d0 = aes0.decrypt(iv, e0) - - e1 = PyCryptoAES.new(key, PyCryptoAES.MODE_CBC, iv=iv).encrypt(pp) - d1 = PyCryptoAES.new(key, PyCryptoAES.MODE_CBC, iv=iv).decrypt(e1) - - assert pp == d0 == d1 - assert e0 == e1 - - for _ in range(10): - iv = bytes(bytearray(random.randint(0, 255) for _ in range(16))) - pp = bytes(bytearray(random.randint(0, 255) for _ in range(16 * 4))) - _test_CBC(key128, iv, pp) - _test_CBC(key192, iv, pp) - _test_CBC(key256, iv, pp) - - -if __name__ == "__main__": - _test() diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index b7ecadc2e..db933e6d5 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -32,6 +32,7 @@ import struct import typing +from PyPDF2.errors import DependencyError from PyPDF2.generic import * @@ -94,8 +95,6 @@ def AES_CBC_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: except ImportError: - from PyPDF2._aes import AESECB, AESCBC - class CryptRC4(CryptBase): def __init__(self, key: bytes) -> None: self.S = list(range(256)) @@ -121,19 +120,13 @@ def decrypt(self, data: bytes) -> bytes: class CryptAES(CryptBase): def __init__(self, key: bytes) -> None: - self.aes = AESCBC(key) + pass def encrypt(self, data: bytes) -> bytes: - iv = bytes(bytearray(random.randint(0, 255) for _ in range(16))) - p = 16 - len(data) % 16 - data += bytes(bytearray(p for _ in range(p))) - return iv + self.aes.encrypt(iv, data) + raise DependencyError("PyCryptodome is required for AES algorithm") def decrypt(self, data: bytes) -> bytes: - iv = data[:16] - data = data[16:] - d = self.aes.decrypt(iv, data) - return d[:-d[-1]] + raise DependencyError("PyCryptodome is required for AES algorithm") def RC4_encrypt(key: bytes, data: bytes) -> bytes: return CryptRC4(key).encrypt(data) @@ -142,16 +135,16 @@ def RC4_decrypt(key: bytes, data: bytes) -> bytes: return CryptRC4(key).decrypt(data) def AES_ECB_encrypt(key: bytes, data: bytes) -> bytes: - return AESECB(key).encrypt(data) + raise DependencyError("PyCryptodome is required for AES algorithm") def AES_ECB_decrypt(key: bytes, data: bytes) -> bytes: - return AESECB(key).decrypt(data) + raise DependencyError("PyCryptodome is required for AES algorithm") def AES_CBC_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes: - return AESCBC(key).encrypt(iv, data) + raise DependencyError("PyCryptodome is required for AES algorithm") def AES_CBC_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: - return AESCBC(key).decrypt(iv, data) + raise DependencyError("PyCryptodome is required for AES algorithm") class CryptFilter: @@ -517,7 +510,7 @@ def compute_Perms_value(key: bytes, p: int, metadata_encrypted: bool) -> bytes: b8 = b'T' if metadata_encrypted else 'F' rr = bytes(random.randrange(0, 256) for _ in range(4)) data = struct.pack(" Date: Thu, 21 Apr 2022 22:11:39 +0800 Subject: [PATCH 08/13] add pycryptodome to `extras_require` --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index 6b42699b6..e8e481389 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,3 +34,6 @@ classifiers = [options] packages = PyPDF2 python_requires = >=2.7 + +[options.extras_require] +crypto = PyCryptodome From fa439c3944fe4ec4a2c03b10e90b16b558c1371f Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Sun, 24 Apr 2022 16:32:17 +0800 Subject: [PATCH 09/13] allow decrypt password to be bytes --- PyPDF2/encryption.py | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index db933e6d5..e13447254 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -182,11 +182,13 @@ def decryptObject(self, obj: PdfObject) -> PdfObject: def _padding(data: bytes) -> bytes: return (data + _PADDING)[:32] -def _bytes(text: str) -> bytes: +def _bytes(value: typing.Union[bytes, str]) -> bytes: + if isinstance(value, bytes): + return value try: - return text.encode('latin-1') + return value.encode('latin-1') except Exception: # noqa - return text.encode('utf-8') + return value.encode('utf-8') class AlgR4: @@ -596,36 +598,36 @@ def _getCrypt(method: str, rc4_key: bytes, aes128_key: bytes, aes256_key: bytes) else: return CryptRC4(rc4_key) - def verify(self, user_pwd: str, owner_pwd: str) -> int: - key = self._user_keys.get(user_pwd) + def verify(self, user_pwd: typing.Union[bytes, str], owner_pwd: typing.Union[bytes, str]) -> int: + up_bytes = _bytes(user_pwd) + op_bytes = _bytes(owner_pwd) + + key = self._user_keys.get(up_bytes) if key: self._key = key return 1 - key = self._owner_keys.get(owner_pwd) + key = self._owner_keys.get(op_bytes) if key: self._key = key return 2 rc = 0 if self.algV <= 4: - key, rc = self.verify_r4(user_pwd, owner_pwd) + key, rc = self.verify_r4(up_bytes, op_bytes) else: - key, rc = self.verify_r5(user_pwd, owner_pwd) + key, rc = self.verify_r5(up_bytes, op_bytes) if rc == 1: self._key = key - self._user_keys[user_pwd] = key + self._user_keys[up_bytes] = key elif rc == 2: self._key = key - self._owner_keys[owner_pwd] = key + self._owner_keys[op_bytes] = key return rc - def verify_r4(self, user_pwd: str, owner_pwd: str) -> typing.Tuple[bytes, int]: - user_pwd1 = _bytes(user_pwd) - owner_pwd1 = _bytes(owner_pwd) - + def verify_r4(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, int]: R = self.entry["/R"] P = self.entry["/P"] P = (P + 0x100000000) % 0x100000000 # maybe < 0 @@ -633,30 +635,27 @@ def verify_r4(self, user_pwd: str, owner_pwd: str) -> typing.Tuple[bytes, int]: o_entry = self.entry["/O"].getObject().original_bytes u_entry = self.entry["/U"].getObject().original_bytes - key = AlgR4.verify_user_password(user_pwd1, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) + key = AlgR4.verify_user_password(user_pwd, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) if key: return key, 1 - key = AlgR4.verify_owner_password(owner_pwd1, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) + key = AlgR4.verify_owner_password(owner_pwd, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) if key: return key, 2 return b"", 0 - def verify_r5(self, user_pwd: str, owner_pwd: str) -> typing.Tuple[bytes, int]: + def verify_r5(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, int]: # TODO: use SASLprep process - user_pwd1 = _bytes(user_pwd) - owner_pwd1 = _bytes(owner_pwd) - o_entry = self.entry["/O"].getObject().original_bytes u_entry = self.entry["/U"].getObject().original_bytes oe_entry = self.entry["/OE"].getObject().original_bytes ue_entry = self.entry["/UE"].getObject().original_bytes rc = 0 - key = AlgR5.verify_user_password(user_pwd1, u_entry, ue_entry) + key = AlgR5.verify_user_password(user_pwd, u_entry, ue_entry) if key: rc = 1 else: - key = AlgR5.verify_owner_password(owner_pwd1, o_entry, oe_entry, u_entry) + key = AlgR5.verify_owner_password(owner_pwd, o_entry, oe_entry, u_entry) if key: rc = 2 if rc == 0: From 2cfece2d4ce98752ac2ed37d985147d54fcfb48b Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Thu, 5 May 2022 11:16:32 +0800 Subject: [PATCH 10/13] make flake8 happy --- PyPDF2/_reader.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/PyPDF2/_reader.py b/PyPDF2/_reader.py index ce72904ca..3580ae484 100644 --- a/PyPDF2/_reader.py +++ b/PyPDF2/_reader.py @@ -32,25 +32,19 @@ import struct import sys import warnings -from hashlib import md5 from sys import version_info from PyPDF2 import utils from PyPDF2._page import PageObject -from PyPDF2._security import _alg33_1, _alg34, _alg35 from PyPDF2.constants import CatalogAttributes as CA from PyPDF2.constants import Core as CO from PyPDF2.constants import DocumentInformationAttributes as DI -from PyPDF2.constants import EncryptionDictAttributes as ED from PyPDF2.constants import PageAttributes as PG from PyPDF2.constants import PagesAttributes as PA -from PyPDF2.constants import StreamAttributes as SA from PyPDF2.constants import TrailerKeys as TK from PyPDF2.errors import DependencyError, PdfReadError, PdfReadWarning, PdfStreamError from PyPDF2.generic import ( ArrayObject, - BooleanObject, - ByteStringObject, Destination, DictionaryObject, Field, @@ -58,9 +52,7 @@ NameObject, NullObject, NumberObject, - StreamObject, TextStringObject, - createStringObject, readNonWhitespace, readObject, ) From 042410b72a292bcab1df3f91aa4c601044516b52 Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Thu, 5 May 2022 11:30:17 +0800 Subject: [PATCH 11/13] tag test_encryption with 'no_py27' --- Tests/test_encryption.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/test_encryption.py b/Tests/test_encryption.py index fc756d418..6284dc7b1 100644 --- a/Tests/test_encryption.py +++ b/Tests/test_encryption.py @@ -7,6 +7,7 @@ RESOURCE_ROOT = os.path.join(PROJECT_ROOT, "Resources") +@pytest.mark.no_py27() @pytest.mark.parametrize( "src", [ @@ -66,6 +67,7 @@ def test_encryption(src): } +@pytest.mark.no_py27() @pytest.mark.parametrize( "names", [ From cc508978af9162f7f211b409ccb9375940696551 Mon Sep 17 00:00:00 2001 From: exiledkingcc Date: Sat, 11 Jun 2022 16:20:52 +0800 Subject: [PATCH 12/13] update for flake8 --- PyPDF2/_reader.py | 16 ++++++- PyPDF2/encryption.py | 97 ++++++++++++++++++++++------------------ tests/test_encryption.py | 4 +- 3 files changed, 69 insertions(+), 48 deletions(-) diff --git a/PyPDF2/_reader.py b/PyPDF2/_reader.py index 12baf82c4..126ee123f 100644 --- a/PyPDF2/_reader.py +++ b/PyPDF2/_reader.py @@ -1054,7 +1054,8 @@ def get_object(self, indirect_reference: IndirectObject) -> Optional[PdfObject]: if not hasattr(self, "_encryption"): raise PdfReadError("file has not been decrypted") # otherwise, decrypt here... - retval = self._encryption.decryptObject(retval, indirect_reference.idnum, indirect_reference.generation) + retval = cast(PdfObject, retval) + retval = self._encryption.decrypt_object(retval, indirect_reference.idnum, indirect_reference.generation) else: warnings.warn( "Object %d %d not defined." @@ -1068,6 +1069,17 @@ def get_object(self, indirect_reference: IndirectObject) -> Optional[PdfObject]: ) return retval + def getObject( + self, indirectReference: IndirectObject + ) -> Optional[PdfObject]: # pragma: no cover + """ + .. deprecated:: 1.28.0 + + Use :meth:`get_object` instead. + """ + deprecate_with_replacement("getObject", "get_object") + return self.get_object(indirectReference) + def read_object_header(self, stream: StreamType) -> Tuple[int, int]: # Should never be necessary to read out whitespace, since the # cross-reference table should put us in the right spot to read the @@ -1590,7 +1602,7 @@ def _decrypt(self, password: Union[str, bytes]) -> int: # https://github.com/mstamy2/PyPDF2/issues/608 id_entry = self.trailer.get(TK.ID) id1_entry = id_entry[0].get_object().original_bytes if id_entry else b"" - encryptEntry = self.trailer[TK.ENCRYPT].get_object() + encryptEntry = cast(DictionaryObject, self.trailer[TK.ENCRYPT].get_object()) encryption = Encryption.read(encryptEntry, id1_entry) # maybe password is owner password # TODO: add/modify api to set owner password diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index a967325f7..c2d8bd1a5 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -30,7 +30,13 @@ import hashlib import random import struct -import typing +from typing import ( + Dict, + Optional, + Tuple, + Union, + cast, +) from PyPDF2.errors import DependencyError from PyPDF2.generic import ( @@ -41,6 +47,7 @@ StreamObject, TextStringObject, createStringObject, + ) @@ -107,7 +114,7 @@ def AES_CBC_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: except ImportError: - class CryptRC4(CryptBase): + class CryptRC4(CryptBase): # type: ignore def __init__(self, key: bytes) -> None: self.S = list(range(256)) j = 0 @@ -130,7 +137,7 @@ def encrypt(self, data: bytes) -> bytes: def decrypt(self, data: bytes) -> bytes: return self.encrypt(data) - class CryptAES(CryptBase): + class CryptAES(CryptBase): # type: ignore def __init__(self, key: bytes) -> None: pass @@ -165,11 +172,11 @@ def __init__(self, stmCrypt: CryptBase, strCrypt: CryptBase, efCrypt: CryptBase) self.strCrypt = strCrypt self.efCrypt = efCrypt - def encryptObject(self, obj: PdfObject) -> PdfObject: + def encrypt_object(self, obj: PdfObject) -> PdfObject: # TODO return NotImplemented - def decryptObject(self, obj: PdfObject) -> PdfObject: + def decrypt_object(self, obj: PdfObject) -> PdfObject: if isinstance(obj, ByteStringObject) or isinstance(obj, TextStringObject): data = self.strCrypt.decrypt(obj.original_bytes) obj = createStringObject(data) @@ -177,10 +184,10 @@ def decryptObject(self, obj: PdfObject) -> PdfObject: obj._data = self.stmCrypt.decrypt(obj._data) elif isinstance(obj, DictionaryObject): for dictkey, value in list(obj.items()): - obj[dictkey] = self.decryptObject(value) + obj[dictkey] = self.decrypt_object(value) elif isinstance(obj, ArrayObject): for i in range(len(obj)): - obj[i] = self.decryptObject(obj[i]) + obj[i] = self.decrypt_object(obj[i]) return obj @@ -196,7 +203,7 @@ def _padding(data: bytes) -> bytes: return (data + _PADDING)[:32] -def _bytes(value: typing.Union[bytes, str]) -> bytes: +def _bytes(value: Union[bytes, str]) -> bytes: if isinstance(value, bytes): return value try: @@ -444,9 +451,10 @@ def verify_user_password(password: bytes, u_value: bytes, ue_value: bytes) -> by tmp_key = hashlib.sha256(password + u_value[40:]).digest() return AES_CBC_decrypt(tmp_key, iv, ue_value) - def verify_perms(key: bytes, perms: bytes, p: int, metadata_encrypted: bool) -> bytes: + @staticmethod + def verify_perms(key: bytes, perms: bytes, p: int, metadata_encrypted: bool) -> bool: """see :func:`verify_owner_password` and :func:`compute_Perms_value`""" - b8 = b'T' if metadata_encrypted else 'F' + b8 = b'T' if metadata_encrypted else b'F' p1 = struct.pack(" typing.Tuple[bytes]: + def compute_U_value(password: bytes, key: bytes) -> Tuple[bytes, bytes]: """ Algorithm 3.8 Computing the encryption dictionary’s U (user password) and UE (user encryption key) values @@ -488,7 +496,7 @@ def compute_U_value(password: bytes, key: bytes) -> typing.Tuple[bytes]: return u_value, ue_value @staticmethod - def compute_O_value(password: bytes, key: bytes, u_value: bytes) -> typing.Tuple[bytes]: + def compute_O_value(password: bytes, key: bytes, u_value: bytes) -> Tuple[bytes, bytes]: """ Algorithm 3.9 Computing the encryption dictionary’s O (owner password) and OE (owner encryption key) values @@ -527,7 +535,7 @@ def compute_Perms_value(key: bytes, p: int, metadata_encrypted: bool) -> bytes: encryption key as the key. The result (16 bytes) is stored as the Perms string, and checked for validity when the file is opened. """ - b8 = b'T' if metadata_encrypted else 'F' + b8 = b'T' if metadata_encrypted else b'F' rr = bytes(random.randrange(0, 256) for _ in range(4)) data = struct.pack(" PdfObject: + def decrypt_object(self, obj: PdfObject, idnum: int, generation: int) -> PdfObject: """decrypt object""" """ @@ -586,6 +594,7 @@ def decryptObject(self, obj: PdfObject, idnum: int, generation: int) -> PdfObjec pack1 = struct.pack(" PdfObjec # for V=5 use AES-256 aes256_key = key - stmCrypt = self._getCrypt(self.StmF, rc4_key, aes128_key, aes256_key) - StrCrypt = self._getCrypt(self.StrF, rc4_key, aes128_key, aes256_key) - efCrypt = self._getCrypt(self.EFF, rc4_key, aes128_key, aes256_key) + stmCrypt = self._get_crypt(self.StmF, rc4_key, aes128_key, aes256_key) + StrCrypt = self._get_crypt(self.StrF, rc4_key, aes128_key, aes256_key) + efCrypt = self._get_crypt(self.EFF, rc4_key, aes128_key, aes256_key) cf = CryptFilter(stmCrypt, StrCrypt, efCrypt) - return cf.decryptObject(obj) + return cf.decrypt_object(obj) @staticmethod - def _getCrypt(method: str, rc4_key: bytes, aes128_key: bytes, aes256_key: bytes) -> CryptBase: + def _get_crypt(method: str, rc4_key: bytes, aes128_key: bytes, aes256_key: bytes) -> CryptBase: if method == "/AESV3": return CryptAES(aes256_key) if method == "/AESV2": @@ -616,7 +625,7 @@ def _getCrypt(method: str, rc4_key: bytes, aes128_key: bytes, aes256_key: bytes) else: return CryptRC4(rc4_key) - def verify(self, user_pwd: typing.Union[bytes, str], owner_pwd: typing.Union[bytes, str]) -> int: + def verify(self, user_pwd: Union[bytes, str], owner_pwd: Union[bytes, str]) -> int: up_bytes = _bytes(user_pwd) op_bytes = _bytes(owner_pwd) @@ -645,13 +654,13 @@ def verify(self, user_pwd: typing.Union[bytes, str], owner_pwd: typing.Union[byt return rc - def verify_r4(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, int]: - R = self.entry["/R"] - P = self.entry["/P"] + def verify_r4(self, user_pwd: bytes, owner_pwd: bytes) -> Tuple[bytes, int]: + R = cast(int, self.entry["/R"]) + P = cast(int, self.entry["/P"]) P = (P + 0x100000000) % 0x100000000 # maybe < 0 metadata_encrypted = self.entry.get("/EncryptMetadata", True) - o_entry = self.entry["/O"].get_object().original_bytes - u_entry = self.entry["/U"].get_object().original_bytes + o_entry = cast(ByteStringObject, self.entry["/O"].get_object()).original_bytes + u_entry = cast(ByteStringObject, self.entry["/U"].get_object()).original_bytes key = AlgR4.verify_user_password(user_pwd, R, self.key_size, o_entry, u_entry, P, self.id1_entry, metadata_encrypted) if key: @@ -661,12 +670,12 @@ def verify_r4(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, in return key, 2 return b"", 0 - def verify_r5(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, int]: + def verify_r5(self, user_pwd: bytes, owner_pwd: bytes) -> Tuple[bytes, int]: # TODO: use SASLprep process - o_entry = self.entry["/O"].get_object().original_bytes - u_entry = self.entry["/U"].get_object().original_bytes - oe_entry = self.entry["/OE"].get_object().original_bytes - ue_entry = self.entry["/UE"].get_object().original_bytes + o_entry = cast(ByteStringObject, self.entry["/O"].get_object()).original_bytes + u_entry = cast(ByteStringObject, self.entry["/U"].get_object()).original_bytes + oe_entry = cast(ByteStringObject, self.entry["/OE"].get_object()).original_bytes + ue_entry = cast(ByteStringObject, self.entry["/UE"].get_object()).original_bytes rc = 0 key = AlgR5.verify_user_password(user_pwd, u_entry, ue_entry) @@ -679,8 +688,8 @@ def verify_r5(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, in if rc == 0: return b"", 0 # verify Perms - perms = self.entry["/Perms"].get_object().original_bytes - P = self.entry["/P"] + perms = cast(ByteStringObject, self.entry["/Perms"].get_object()).original_bytes + P = cast(int, self.entry["/P"]) P = (P + 0x100000000) % 0x100000000 # maybe < 0 metadata_encrypted = self.entry.get("/EncryptMetadata", True) if not AlgR5.verify_perms(key, perms, P, metadata_encrypted): @@ -688,7 +697,7 @@ def verify_r5(self, user_pwd: bytes, owner_pwd: bytes) -> typing.Tuple[bytes, in return key, rc @staticmethod - def read(encryption_entry: DictionaryObject, first_id_entry: bytes = None) -> "Encryption": + def read(encryption_entry: DictionaryObject, first_id_entry: bytes) -> "Encryption": filter = encryption_entry.get("/Filter") if filter != "/Standard": raise NotImplementedError("only Standard PDF encryption handler is available") @@ -710,22 +719,22 @@ def read(encryption_entry: DictionaryObject, first_id_entry: bytes = None) -> "E EFF = encryption_entry.get("/EFF", StmF) if StmF != "/Identity": - StmF = filters[StmF]["/CFM"] + StmF = filters[StmF]["/CFM"] # type: ignore if StrF != "/Identity": - StrF = filters[StrF]["/CFM"] + StrF = filters[StrF]["/CFM"] # type: ignore if EFF != "/Identity": - EFF = filters[EFF]["/CFM"] + EFF = filters[EFF]["/CFM"] # type: ignore allowed_methods = ("/Identity", "/V2", "/AESV2", "/AESV3") if StmF not in allowed_methods: - raise NotImplementedError("StmF Method %s NOT supported!" % StmF) + raise NotImplementedError("StmF Method {StmF} NOT supported!") if StrF not in allowed_methods: - raise NotImplementedError("StrF Method %s NOT supported!" % StrF) + raise NotImplementedError(f"StrF Method {StrF} NOT supported!") if EFF not in allowed_methods: - raise NotImplementedError("EFF Method %s NOT supported!" % EFF) + raise NotImplementedError(f"EFF Method {EFF} NOT supported!") - R = encryption_entry["/R"] + R = cast(int, encryption_entry["/R"]) if R > 5: - raise NotImplementedError("encryption R={} NOT supported!".format(R)) + raise NotImplementedError(f"encryption R={R} NOT supported!") return Encryption(V, encryption_entry, first_id_entry, StmF, StrF, EFF) diff --git a/tests/test_encryption.py b/tests/test_encryption.py index 45dc76e0e..f83be13a0 100644 --- a/tests/test_encryption.py +++ b/tests/test_encryption.py @@ -47,9 +47,9 @@ def test_encryption(src): with open(src, "rb") as inputfile: ipdf = PyPDF2.PdfReader(inputfile) if src.endswith("enc0.pdf"): - assert ipdf.is_encrypted == False + assert not ipdf.is_encrypted else: - assert ipdf.is_encrypted == True + assert ipdf.is_encrypted ipdf.decrypt("asdfzxcv") assert len(ipdf.pages) == 1 dd = dict(ipdf.metadata) From 6172a5153211a330f138d600210188b3b12631ee Mon Sep 17 00:00:00 2001 From: Martin Thoma Date: Sun, 19 Jun 2022 08:16:42 +0200 Subject: [PATCH 13/13] Add pragma no-cover to base class --- PyPDF2/encryption.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PyPDF2/encryption.py b/PyPDF2/encryption.py index c2d8bd1a5..cfe925850 100644 --- a/PyPDF2/encryption.py +++ b/PyPDF2/encryption.py @@ -52,10 +52,10 @@ class CryptBase: - def encrypt(self, data: bytes) -> bytes: + def encrypt(self, data: bytes) -> bytes: # pragma: no cover return data - def decrypt(self, data: bytes) -> bytes: + def decrypt(self, data: bytes) -> bytes: # pragma: no cover return data