예제 #1
0
        private byte[] ComputeUserPasswordValue(int keyLength, byte[] documentId, byte[] encryptionKey)
        {
            // Algorithm 3.5, Computing the encryption dictionary's U (user password) value

            // (2, 3) Join the fixed padding and the document identifier
            byte[] hash = new byte[PADDING_32.Length + documentId.Length];
            Array.Copy(PADDING_32, 0, hash, 0, PADDING_32.Length);
            Array.Copy(documentId, 0, hash, PADDING_32.Length, documentId.Length);

            // (3) Hash using MD5
            hash = _md5.ComputeHash(hash);

            // (4, 5) Iterate 20 times
            byte[] rc4Key = new byte[encryptionKey.Length];
            for (int i = 0; i < 20; i++)
            {
                for (int j = 0; j < encryptionKey.Length; ++j)
                {
                    rc4Key[j] = (byte)(encryptionKey[j] ^ i);
                }

                hash = RC4.Transform(rc4Key, hash);
            }

            // (6) First 16 bytes is the hash result and the remainder is zero's
            byte[] userKey = new byte[32];
            Array.Copy(hash, 0, userKey, 0, 16);
            return(userKey);
        }
예제 #2
0
        private byte[] ComputeOwnerPasswordValue(int keyLength, byte[] ownerKey)
        {
            // Algorithm 3.3, Computing the encryption dictionary's O (owner password) value

            // (1) Pad the owner password (use the pad because we do not care about a users password)
            byte[] ownerPasword = new byte[32];
            Array.Copy(PADDING_32, ownerPasword, 32);

            // (2) Initialize the MD5
            ownerPasword = _md5.ComputeHash(ownerPasword);

            // (3) Rehash 50 times
            int blockLength = keyLength / 8;

            byte[] block = new byte[blockLength];
            Array.Copy(ownerPasword, 0, block, 0, block.Length);
            for (int i = 0; i < 50; i++)
            {
                Array.Copy(_md5.ComputeHash(block), 0, block, 0, block.Length);
            }

            // (4) RC4 key
            byte[] rc4Key = new byte[blockLength];

            // (5) Pad the user password
            byte[] userPassword = new byte[32];
            Array.Copy(PADDING_32, userPassword, 32);

            // (6, 7) Iterate 20 times
            for (int i = 0; i < 20; i++)
            {
                for (int j = 0; j < blockLength; ++j)
                {
                    rc4Key[j] = (byte)(block[j] ^ i);
                }

                ownerKey = RC4.Transform(rc4Key, ownerKey);
            }

            return(ownerKey);
        }
예제 #3
0
        private byte[] DecodeBytes(PdfObject obj, byte[] bytes)
        {
            PdfIndirectObject indirectObject = obj.TypedParent <PdfIndirectObject>();

            if (indirectObject == null)
            {
                throw new ApplicationException($"Cannot decrypt a string that is not inside an indirect object.");
            }

            // Create bytes that need hashing by combining the encryption key with the indirect object numbers
            byte[] key = new byte[_encryptionKey.Length + 5];
            Array.Copy(_encryptionKey, 0, key, 0, _encryptionKey.Length);
            int index = _encryptionKey.Length;
            int id    = indirectObject.Id;

            key[index++] = (byte)(id >> 0);
            key[index++] = (byte)(id >> 8);
            key[index++] = (byte)(id >> 16);
            int gen = indirectObject.Gen;

            key[index++] = (byte)(gen >> 0);
            key[index++] = (byte)(gen >> 8);

            // MD5 hash the bytes to get raw decrypt key
            key = _md5.ComputeHash(key);

            // Limit check the decrypt key length
            int keyLength = _encryptionKey.Length + 5;

            if (keyLength > 16)
            {
                keyLength = 16;
            }

            // Create the RC4 key
            byte[] rc4Key = new Byte[keyLength];
            Array.Copy(key, 0, rc4Key, 0, keyLength);
            return(RC4.Transform(rc4Key, bytes));
        }