예제 #1
0
        private static bool IsUserPassword(byte[] passwordBytes, EncryptionDictionary encryptionDictionary, int length, byte[] documentIdBytes)
        {
            if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6)
            {
                return(IsUserPasswordRevision5And6(passwordBytes, encryptionDictionary));
            }

            // 1. Create an encryption key based on the user password string.
            var calculatedEncryptionKey = CalculateKeyRevisions2To4(passwordBytes, encryptionDictionary, length, documentIdBytes);

            byte[] output;

            if (encryptionDictionary.Revision >= 3)
            {
                using (var md5 = MD5.Create())
                {
                    // 2. Initialize the MD5 hash function and pass the 32-byte padding string.
                    UpdateMd5(md5, PaddingBytes);

                    // 3.   Pass the first element of the file identifier array to the hash function and finish the hash.
                    UpdateMd5(md5, documentIdBytes);
                    md5.TransformFinalBlock(EmptyArray <byte> .Instance, 0, 0);

                    var result = md5.Hash;

                    // 4. Encrypt the 16-byte result of the hash, using an RC4 encryption function with the encryption key from step 1.
                    var temp = RC4.Encrypt(calculatedEncryptionKey, result);

                    // 5. Do the following 19 times:
                    for (byte i = 1; i <= 19; i++)
                    {
                        // 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 (from step 1)
                        // and performing an XOR operation between that byte and the single-byte value of the iteration counter.
                        var key = calculatedEncryptionKey.Select(x => (byte)(x ^ i)).ToArray();
                        temp = RC4.Encrypt(key, temp);
                    }

                    output = temp;
                }
            }
            else
            {
                // 2. Encrypt the 32-byte padding string using an RC4 encryption function with the encryption key from the preceding step.
                output = RC4.Encrypt(calculatedEncryptionKey, PaddingBytes);
            }

            if (encryptionDictionary.Revision >= 3)
            {
                return(encryptionDictionary.UserBytes.Take(16).SequenceEqual(output.Take(16)));
            }

            return(encryptionDictionary.UserBytes.SequenceEqual(output));
        }
예제 #2
0
        private byte[] DecryptData(byte[] data, IndirectReference reference)
        {
            if (useAes && encryptionKey.Length == 32)
            {
                return(AesEncryptionHelper.Decrypt(data, encryptionKey));
            }

            var finalKey = GetObjectKey(reference);

            if (useAes)
            {
                return(AesEncryptionHelper.Decrypt(data, finalKey));
            }

            return(RC4.Encrypt(finalKey, data));
        }
예제 #3
0
        private static bool IsOwnerPassword(byte[] passwordBytes, EncryptionDictionary encryptionDictionary, int length, byte[] documentIdBytes,
                                            out byte[] userPassword)
        {
            userPassword = null;

            if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6)
            {
                return(IsOwnerPasswordRevision5And6(passwordBytes, encryptionDictionary));
            }

            // 1. Pad or truncate the owner password string, if there is no owner password use the user password instead.
            var paddedPassword = GetPaddedPassword(passwordBytes);

            using (var md5 = MD5.Create())
            {
                // 2. Initialize the MD5 hash function and pass the result of step 1 as input.
                var hash = md5.ComputeHash(paddedPassword);

                // 3. (Revision 3 or greater) Do the following 50 times:
                if (encryptionDictionary.Revision >= 3)
                {
                    // Take the output from the previous MD5 hash and pass it as input into a new MD5 hash.
                    for (var i = 0; i < 50; i++)
                    {
                        hash = md5.ComputeHash(md5.Hash);
                    }
                }

                // 4. Create an RC4 encryption key using the first n bytes of the output from the final MD5 hash,
                // where n is always 5 for revision 2 but for revision 3 or greater depends on the value of the encryption dictionary's Length entry.
                var key = hash.Take(length).ToArray();

                if (encryptionDictionary.Revision == 2)
                {
                    // 5. (Revision 2 only) Decrypt the value of the encryption dictionary's owner entry,
                    // using an RC4 encryption function with the encryption key computed in step 1 - 4.
                    userPassword = RC4.Encrypt(key, encryptionDictionary.OwnerBytes);
                }
                else
                {
                    // 5. (Revision 3 or greater) Do the following 20 times:
                    byte[] output = null;
                    for (var i = 0; i < 20; i++)
                    {
                        // Generate a per iteration key by taking the original key and performing an XOR operation between each
                        // byte of the key and the single-byte value of the iteration counter (from 19 to 0).
                        var keyIter = key.Select(x => (byte)(x ^ (19 - i))).ToArray();

                        if (i == 0)
                        {
                            output = encryptionDictionary.OwnerBytes;
                        }

                        // Decrypt the value of the encryption dictionary's owner entry (first iteration)
                        // or the output from the previous iteration using an RC4 encryption function.
                        output = RC4.Encrypt(keyIter, output);
                    }

                    userPassword = output;
                }

                // 6. The result of step 5 purports to be the user password.
                // Authenticate this user password, if it is correct, the password supplied is the owner password.
                var result = IsUserPassword(userPassword, encryptionDictionary, length, documentIdBytes);

                return(result);
            }
        }