virtual public bool ReadKey(PdfDictionary enc, byte[] password)
        {
            if (password == null)
            {
                password = new byte[0];
            }
            byte[] oValue  = DocWriter.GetISOBytes(enc.Get(PdfName.O).ToString());
            byte[] uValue  = DocWriter.GetISOBytes(enc.Get(PdfName.U).ToString());
            byte[] oeValue = DocWriter.GetISOBytes(enc.Get(PdfName.OE).ToString());
            byte[] ueValue = DocWriter.GetISOBytes(enc.Get(PdfName.UE).ToString());
            byte[] perms   = DocWriter.GetISOBytes(enc.Get(PdfName.PERMS).ToString());

            PdfNumber pValue = (PdfNumber)enc.Get(PdfName.P);

            this.oeKey = oeValue;
            this.ueKey = ueValue;
            this.perms = perms;

            this.ownerKey = oValue;
            this.userKey  = uValue;

            this.permissions = pValue.LongValue;

            bool    isUserPass = false;
            IDigest md         = DigestUtilities.GetDigest("SHA-256");

            md.BlockUpdate(password, 0, Math.Min(password.Length, 127));
            md.BlockUpdate(oValue, VALIDATION_SALT_OFFSET, SALT_LENGHT);
            md.BlockUpdate(uValue, 0, OU_LENGHT);
            byte[]            hash        = DigestUtilities.DoFinal(md);
            bool              isOwnerPass = CompareArray(hash, oValue, 32);
            AESCipherCBCnoPad ac;

            if (isOwnerPass)
            {
                md.BlockUpdate(password, 0, Math.Min(password.Length, 127));
                md.BlockUpdate(oValue, KEY_SALT_OFFSET, SALT_LENGHT);
                md.BlockUpdate(uValue, 0, OU_LENGHT);
                md.DoFinal(hash, 0);
                ac  = new AESCipherCBCnoPad(false, hash);
                key = ac.ProcessBlock(oeValue, 0, oeValue.Length);
            }
            else
            {
                md.BlockUpdate(password, 0, Math.Min(password.Length, 127));
                md.BlockUpdate(uValue, VALIDATION_SALT_OFFSET, SALT_LENGHT);
                md.DoFinal(hash, 0);
                isUserPass = CompareArray(hash, uValue, 32);
                if (!isUserPass)
                {
                    throw new BadPasswordException(MessageLocalization.GetComposedMessage("bad.user.password"));
                }
                md.BlockUpdate(password, 0, Math.Min(password.Length, 127));
                md.BlockUpdate(uValue, KEY_SALT_OFFSET, SALT_LENGHT);
                md.DoFinal(hash, 0);
                ac  = new AESCipherCBCnoPad(false, hash);
                key = ac.ProcessBlock(ueValue, 0, ueValue.Length);
            }
            ac = new AESCipherCBCnoPad(false, key);
            byte[] decPerms = ac.ProcessBlock(perms, 0, perms.Length);
            if (decPerms[9] != (byte)'a' || decPerms[10] != (byte)'d' || decPerms[11] != (byte)'b')
            {
                throw new BadPasswordException(MessageLocalization.GetComposedMessage("bad.user.password"));
            }
            permissions = (decPerms[0] & 0xff) | ((decPerms[1] & 0xff) << 8)
                          | ((decPerms[2] & 0xff) << 16) | ((decPerms[2] & 0xff) << 24);
            encryptMetadata = decPerms[8] == (byte)'T';
            return(isOwnerPass);
        }
Exemple #2
0
        // gets keylength and revision and uses revison to choose the initial values for permissions
        virtual public void SetupAllKeys(byte[] userPassword, byte[] ownerPassword, int permissions)
        {
            if (ownerPassword == null || ownerPassword.Length == 0)
            {
                ownerPassword = DigestAlgorithms.Digest("MD5", CreateDocumentId());
            }
            md5.Reset();
            permissions     |= (int)((revision == STANDARD_ENCRYPTION_128 || revision == AES_128 || revision == AES_256) ? (uint)0xfffff0c0 : (uint)0xffffffc0);
            permissions     &= unchecked ((int)0xfffffffc);
            this.permissions = permissions;
            if (revision == AES_256)
            {
                if (userPassword == null)
                {
                    userPassword = new byte[0];
                }
                documentID = CreateDocumentId();
                byte[] uvs = IVGenerator.GetIV(8);
                byte[] uks = IVGenerator.GetIV(8);
                key = IVGenerator.GetIV(32);
                // Algorithm 3.8.1
                IDigest md = DigestUtilities.GetDigest("SHA-256");
                md.BlockUpdate(userPassword, 0, Math.Min(userPassword.Length, 127));
                md.BlockUpdate(uvs, 0, uvs.Length);
                userKey = new byte[48];
                md.DoFinal(userKey, 0);
                System.Array.Copy(uvs, 0, userKey, 32, 8);
                System.Array.Copy(uks, 0, userKey, 40, 8);
                // Algorithm 3.8.2
                md.BlockUpdate(userPassword, 0, Math.Min(userPassword.Length, 127));
                md.BlockUpdate(uks, 0, uks.Length);
                byte[] tempDigest = new byte[32];
                md.DoFinal(tempDigest, 0);
                AESCipherCBCnoPad ac = new AESCipherCBCnoPad(true, tempDigest);
                ueKey = ac.ProcessBlock(key, 0, key.Length);
                // Algorithm 3.9.1
                byte[] ovs = IVGenerator.GetIV(8);
                byte[] oks = IVGenerator.GetIV(8);
                md.BlockUpdate(ownerPassword, 0, Math.Min(ownerPassword.Length, 127));
                md.BlockUpdate(ovs, 0, ovs.Length);
                md.BlockUpdate(userKey, 0, userKey.Length);
                ownerKey = new byte[48];
                md.DoFinal(ownerKey, 0);
                System.Array.Copy(ovs, 0, ownerKey, 32, 8);
                System.Array.Copy(oks, 0, ownerKey, 40, 8);
                // Algorithm 3.9.2
                md.BlockUpdate(ownerPassword, 0, Math.Min(ownerPassword.Length, 127));
                md.BlockUpdate(oks, 0, oks.Length);
                md.BlockUpdate(userKey, 0, userKey.Length);
                md.DoFinal(tempDigest, 0);
                ac    = new AESCipherCBCnoPad(true, tempDigest);
                oeKey = ac.ProcessBlock(key, 0, key.Length);
                // Algorithm 3.10
                byte[] permsp = IVGenerator.GetIV(16);
                permsp[0]  = (byte)permissions;
                permsp[1]  = (byte)(permissions >> 8);
                permsp[2]  = (byte)(permissions >> 16);
                permsp[3]  = (byte)(permissions >> 24);
                permsp[4]  = (byte)(255);
                permsp[5]  = (byte)(255);
                permsp[6]  = (byte)(255);
                permsp[7]  = (byte)(255);
                permsp[8]  = encryptMetadata ? (byte)'T' : (byte)'F';
                permsp[9]  = (byte)'a';
                permsp[10] = (byte)'d';
                permsp[11] = (byte)'b';
                ac         = new AESCipherCBCnoPad(true, key);
                perms      = ac.ProcessBlock(permsp, 0, permsp.Length);
            }
            else
            {
                //PDF refrence 3.5.2 Standard Security Handler, Algorithum 3.3-1
                //If there is no owner password, use the user password instead.
                byte[] userPad  = PadPassword(userPassword);
                byte[] ownerPad = PadPassword(ownerPassword);

                this.ownerKey = ComputeOwnerKey(userPad, ownerPad);
                documentID    = CreateDocumentId();
                SetupByUserPad(this.documentID, userPad, this.ownerKey, permissions);
            }
        }
 private void InitKeyAndFillDictionary(PdfDictionary encryptionDictionary, byte[] userPassword, byte[] ownerPassword
                                       , int permissions, bool encryptMetadata, bool embeddedFilesOnly)
 {
     ownerPassword = GenerateOwnerPasswordIfNullOrEmpty(ownerPassword);
     permissions  |= PERMS_MASK_1_FOR_REVISION_3_OR_GREATER;
     permissions  &= PERMS_MASK_2;
     try {
         byte[] userKey;
         byte[] ownerKey;
         byte[] ueKey;
         byte[] oeKey;
         byte[] aes256Perms;
         if (userPassword == null)
         {
             userPassword = new byte[0];
         }
         else
         {
             if (userPassword.Length > 127)
             {
                 userPassword = iText.IO.Util.JavaUtil.ArraysCopyOf(userPassword, 127);
             }
         }
         if (ownerPassword.Length > 127)
         {
             ownerPassword = iText.IO.Util.JavaUtil.ArraysCopyOf(ownerPassword, 127);
         }
         // first 8 bytes are validation salt; second 8 bytes are key salt
         byte[] userValAndKeySalt  = IVGenerator.GetIV(16);
         byte[] ownerValAndKeySalt = IVGenerator.GetIV(16);
         nextObjectKey     = IVGenerator.GetIV(32);
         nextObjectKeySize = 32;
         byte[] hash;
         // Algorithm 8.1
         hash    = ComputeHash(userPassword, userValAndKeySalt, 0, 8);
         userKey = iText.IO.Util.JavaUtil.ArraysCopyOf(hash, 48);
         System.Array.Copy(userValAndKeySalt, 0, userKey, 32, 16);
         // Algorithm 8.2
         hash = ComputeHash(userPassword, userValAndKeySalt, 8, 8);
         AESCipherCBCnoPad ac = new AESCipherCBCnoPad(true, hash);
         ueKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length);
         // Algorithm 9.1
         hash     = ComputeHash(ownerPassword, ownerValAndKeySalt, 0, 8, userKey);
         ownerKey = iText.IO.Util.JavaUtil.ArraysCopyOf(hash, 48);
         System.Array.Copy(ownerValAndKeySalt, 0, ownerKey, 32, 16);
         // Algorithm 9.2
         hash  = ComputeHash(ownerPassword, ownerValAndKeySalt, 8, 8, userKey);
         ac    = new AESCipherCBCnoPad(true, hash);
         oeKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length);
         // Algorithm 10
         byte[] permsp = IVGenerator.GetIV(16);
         permsp[0]            = (byte)permissions;
         permsp[1]            = (byte)(permissions >> 8);
         permsp[2]            = (byte)(permissions >> 16);
         permsp[3]            = (byte)(permissions >> 24);
         permsp[4]            = (byte)(255);
         permsp[5]            = (byte)(255);
         permsp[6]            = (byte)(255);
         permsp[7]            = (byte)(255);
         permsp[8]            = encryptMetadata ? (byte)'T' : (byte)'F';
         permsp[9]            = (byte)'a';
         permsp[10]           = (byte)'d';
         permsp[11]           = (byte)'b';
         ac                   = new AESCipherCBCnoPad(true, nextObjectKey);
         aes256Perms          = ac.ProcessBlock(permsp, 0, permsp.Length);
         this.permissions     = permissions;
         this.encryptMetadata = encryptMetadata;
         SetStandardHandlerDicEntries(encryptionDictionary, userKey, ownerKey);
         SetAES256DicEntries(encryptionDictionary, oeKey, ueKey, aes256Perms, encryptMetadata, embeddedFilesOnly);
     }
     catch (Exception ex) {
         throw new PdfException(PdfException.PdfEncryption, ex);
     }
 }
        /// <exception cref="Org.BouncyCastle.Security.SecurityUtilityException"/>
        private byte[] ComputeHash(byte[] password, byte[] salt, int saltOffset, int saltLen, byte[] userKey)
        {
            IDigest mdSha256 = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-256");

            mdSha256.Update(password);
            mdSha256.Update(salt, saltOffset, saltLen);
            if (userKey != null)
            {
                mdSha256.Update(userKey);
            }
            byte[] k = mdSha256.Digest();
            if (isPdf2)
            {
                // See 7.6.4.3.3 "Algorithm 2.B"
                IDigest mdSha384          = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-384");
                IDigest mdSha512          = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-512");
                int     userKeyLen        = userKey != null ? userKey.Length : 0;
                int     passAndUserKeyLen = password.Length + userKeyLen;
                // k1 repetition length
                int k1RepLen;
                int roundNum = 0;
                while (true)
                {
                    // a)
                    k1RepLen = passAndUserKeyLen + k.Length;
                    byte[] k1 = new byte[k1RepLen * 64];
                    System.Array.Copy(password, 0, k1, 0, password.Length);
                    System.Array.Copy(k, 0, k1, password.Length, k.Length);
                    if (userKey != null)
                    {
                        System.Array.Copy(userKey, 0, k1, password.Length + k.Length, userKeyLen);
                    }
                    for (int i = 1; i < 64; ++i)
                    {
                        System.Array.Copy(k1, 0, k1, k1RepLen * i, k1RepLen);
                    }
                    // b)
                    AESCipherCBCnoPad cipher = new AESCipherCBCnoPad(true, iText.IO.Util.JavaUtil.ArraysCopyOf(k, 16), iText.IO.Util.JavaUtil.ArraysCopyOfRange
                                                                         (k, 16, 32));
                    byte[] e = cipher.ProcessBlock(k1, 0, k1.Length);
                    // c)
                    IDigest    md        = null;
                    BigInteger i_1       = new BigInteger(1, iText.IO.Util.JavaUtil.ArraysCopyOf(e, 16));
                    int        remainder = i_1.Remainder(BigInteger.ValueOf(3)).IntValue;
                    switch (remainder)
                    {
                    case 0: {
                        md = mdSha256;
                        break;
                    }

                    case 1: {
                        md = mdSha384;
                        break;
                    }

                    case 2: {
                        md = mdSha512;
                        break;
                    }
                    }
                    // d)
                    k = md.Digest(e);
                    ++roundNum;
                    if (roundNum > 63)
                    {
                        // e)
                        int condVal = e[e.Length - 1] & 0xFF;
                        // interpreting last byte as unsigned integer
                        if (condVal <= roundNum - 32)
                        {
                            break;
                        }
                    }
                }
                k = k.Length == 32 ? k : iText.IO.Util.JavaUtil.ArraysCopyOf(k, 32);
            }
            return(k);
        }
 private void InitKeyAndReadDictionary(PdfDictionary encryptionDictionary, byte[] password)
 {
     try {
         if (password == null)
         {
             password = new byte[0];
         }
         else
         {
             if (password.Length > 127)
             {
                 password = iText.IO.Util.JavaUtil.ArraysCopyOf(password, 127);
             }
         }
         isPdf2 = encryptionDictionary.GetAsNumber(PdfName.R).GetValue() == 6;
         byte[]    oValue  = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.O));
         byte[]    uValue  = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.U));
         byte[]    oeValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.OE));
         byte[]    ueValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.UE));
         byte[]    perms   = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.Perms));
         PdfNumber pValue  = (PdfNumber)encryptionDictionary.Get(PdfName.P);
         this.permissions = pValue.LongValue();
         byte[] hash;
         hash = ComputeHash(password, oValue, VALIDATION_SALT_OFFSET, SALT_LENGTH, uValue);
         usedOwnerPassword = CompareArray(hash, oValue, 32);
         if (usedOwnerPassword)
         {
             hash = ComputeHash(password, oValue, KEY_SALT_OFFSET, SALT_LENGTH, uValue);
             AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash);
             nextObjectKey = ac.ProcessBlock(oeValue, 0, oeValue.Length);
         }
         else
         {
             hash = ComputeHash(password, uValue, VALIDATION_SALT_OFFSET, SALT_LENGTH);
             if (!CompareArray(hash, uValue, 32))
             {
                 throw new BadPasswordException(PdfException.BadUserPassword);
             }
             hash = ComputeHash(password, uValue, KEY_SALT_OFFSET, SALT_LENGTH);
             AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash);
             nextObjectKey = ac.ProcessBlock(ueValue, 0, ueValue.Length);
         }
         nextObjectKeySize = 32;
         AESCipherCBCnoPad ac_1     = new AESCipherCBCnoPad(false, nextObjectKey);
         byte[]            decPerms = ac_1.ProcessBlock(perms, 0, perms.Length);
         if (decPerms[9] != (byte)'a' || decPerms[10] != (byte)'d' || decPerms[11] != (byte)'b')
         {
             throw new BadPasswordException(PdfException.BadUserPassword);
         }
         int permissionsDecoded = (decPerms[0] & 0xff) | ((decPerms[1] & 0xff) << 8) | ((decPerms[2] & 0xff) << 16)
                                  | ((decPerms[3] & 0xff) << 24);
         bool encryptMetadata      = decPerms[8] == (byte)'T';
         bool?encryptMetadataEntry = encryptionDictionary.GetAsBool(PdfName.EncryptMetadata);
         if (permissionsDecoded != permissions || encryptMetadataEntry != null && encryptMetadata != encryptMetadataEntry
             )
         {
             ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Crypto.Securityhandler.StandardHandlerUsingAes256));
             logger.Error(iText.IO.LogMessageConstant.ENCRYPTION_ENTRIES_P_AND_ENCRYPT_METADATA_NOT_CORRESPOND_PERMS_ENTRY
                          );
         }
         this.permissions     = permissionsDecoded;
         this.encryptMetadata = encryptMetadata;
     }
     catch (BadPasswordException ex) {
         throw;
     }
     catch (Exception ex) {
         throw new PdfException(PdfException.PdfEncryption, ex);
     }
 }
Exemple #6
0
 private void InitKeyAndFillDictionary(PdfDictionary encryptionDictionary, byte[] userPassword, byte[] ownerPassword
                                       , int permissions, bool encryptMetadata, bool embeddedFilesOnly)
 {
     ownerPassword = GenerateOwnerPasswordIfNullOrEmpty(ownerPassword);
     permissions  |= PERMS_MASK_1_FOR_REVISION_3_OR_GREATER;
     permissions  &= PERMS_MASK_2;
     try {
         byte[] userKey;
         byte[] ownerKey;
         byte[] ueKey;
         byte[] oeKey;
         byte[] aes256Perms;
         if (userPassword == null)
         {
             userPassword = new byte[0];
         }
         byte[] uvs = IVGenerator.GetIV(8);
         byte[] uks = IVGenerator.GetIV(8);
         nextObjectKey     = IVGenerator.GetIV(32);
         nextObjectKeySize = 32;
         // Algorithm 3.8.1
         IDigest md = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-256");
         md.Update(userPassword, 0, Math.Min(userPassword.Length, 127));
         md.Update(uvs);
         userKey = new byte[48];
         md.Digest(userKey, 0, 32);
         System.Array.Copy(uvs, 0, userKey, 32, 8);
         System.Array.Copy(uks, 0, userKey, 40, 8);
         // Algorithm 3.8.2
         md.Update(userPassword, 0, Math.Min(userPassword.Length, 127));
         md.Update(uks);
         AESCipherCBCnoPad ac = new AESCipherCBCnoPad(true, md.Digest());
         ueKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length);
         // Algorithm 3.9.1
         byte[] ovs = IVGenerator.GetIV(8);
         byte[] oks = IVGenerator.GetIV(8);
         md.Update(ownerPassword, 0, Math.Min(ownerPassword.Length, 127));
         md.Update(ovs);
         md.Update(userKey);
         ownerKey = new byte[48];
         md.Digest(ownerKey, 0, 32);
         System.Array.Copy(ovs, 0, ownerKey, 32, 8);
         System.Array.Copy(oks, 0, ownerKey, 40, 8);
         // Algorithm 3.9.2
         md.Update(ownerPassword, 0, Math.Min(ownerPassword.Length, 127));
         md.Update(oks);
         md.Update(userKey);
         ac    = new AESCipherCBCnoPad(true, md.Digest());
         oeKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length);
         // Algorithm 3.10
         byte[] permsp = IVGenerator.GetIV(16);
         permsp[0]            = (byte)permissions;
         permsp[1]            = (byte)(permissions >> 8);
         permsp[2]            = (byte)(permissions >> 16);
         permsp[3]            = (byte)(permissions >> 24);
         permsp[4]            = (byte)(255);
         permsp[5]            = (byte)(255);
         permsp[6]            = (byte)(255);
         permsp[7]            = (byte)(255);
         permsp[8]            = encryptMetadata ? (byte)'T' : (byte)'F';
         permsp[9]            = (byte)'a';
         permsp[10]           = (byte)'d';
         permsp[11]           = (byte)'b';
         ac                   = new AESCipherCBCnoPad(true, nextObjectKey);
         aes256Perms          = ac.ProcessBlock(permsp, 0, permsp.Length);
         this.permissions     = permissions;
         this.encryptMetadata = encryptMetadata;
         SetStandardHandlerDicEntries(encryptionDictionary, userKey, ownerKey);
         SetAES256DicEntries(encryptionDictionary, oeKey, ueKey, aes256Perms, encryptMetadata, embeddedFilesOnly);
     }
     catch (Exception ex) {
         throw new PdfException(PdfException.PdfEncryption, ex);
     }
 }
Exemple #7
0
 private void InitKeyAndReadDictionary(PdfDictionary encryptionDictionary, byte[] password)
 {
     try {
         if (password == null)
         {
             password = new byte[0];
         }
         byte[]    oValue  = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.O));
         byte[]    uValue  = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.U));
         byte[]    oeValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.OE));
         byte[]    ueValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.UE));
         byte[]    perms   = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.Perms));
         PdfNumber pValue  = (PdfNumber)encryptionDictionary.Get(PdfName.P);
         this.permissions = pValue.LongValue();
         IDigest md = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-256");
         md.Update(password, 0, Math.Min(password.Length, 127));
         md.Update(oValue, VALIDATION_SALT_OFFSET, SALT_LENGTH);
         md.Update(uValue, 0, OU_LENGTH);
         byte[] hash = md.Digest();
         usedOwnerPassword = CompareArray(hash, oValue, 32);
         if (usedOwnerPassword)
         {
             md.Update(password, 0, Math.Min(password.Length, 127));
             md.Update(oValue, KEY_SALT_OFFSET, SALT_LENGTH);
             md.Update(uValue, 0, OU_LENGTH);
             hash = md.Digest();
             AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash);
             nextObjectKey = ac.ProcessBlock(oeValue, 0, oeValue.Length);
         }
         else
         {
             md.Update(password, 0, Math.Min(password.Length, 127));
             md.Update(uValue, VALIDATION_SALT_OFFSET, SALT_LENGTH);
             hash = md.Digest();
             if (!CompareArray(hash, uValue, 32))
             {
                 throw new BadPasswordException(PdfException.BadUserPassword);
             }
             md.Update(password, 0, Math.Min(password.Length, 127));
             md.Update(uValue, KEY_SALT_OFFSET, SALT_LENGTH);
             hash = md.Digest();
             AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash);
             nextObjectKey = ac.ProcessBlock(ueValue, 0, ueValue.Length);
         }
         nextObjectKeySize = 32;
         AESCipherCBCnoPad ac_1     = new AESCipherCBCnoPad(false, nextObjectKey);
         byte[]            decPerms = ac_1.ProcessBlock(perms, 0, perms.Length);
         if (decPerms[9] != (byte)'a' || decPerms[10] != (byte)'d' || decPerms[11] != (byte)'b')
         {
             throw new BadPasswordException(PdfException.BadUserPassword);
         }
         permissions = (decPerms[0] & 0xff) | ((decPerms[1] & 0xff) << 8) | ((decPerms[2] & 0xff) << 16) | ((decPerms
                                                                                                             [2] & 0xff) << 24);
         encryptMetadata = decPerms[8] == (byte)'T';
     }
     catch (BadPasswordException ex) {
         throw;
     }
     catch (Exception ex) {
         throw new PdfException(PdfException.PdfEncryption, ex);
     }
 }