private byte[] checkUserPassword(
            byte[] userPassword, byte[] firstDocIdValue, int keyBitLength,
            int revision, byte[] oValue, byte[] uValue, int pValue,
            boolean encryptMetadata)
            throws
            GeneralSecurityException,
            EncryptionUnsupportedByProductException,
            PDFParseException {

        // Algorithm 3.6: Authenticating the user password

        // Step 1: Perform all but the last step of Algorithm 3.4 (Revision 2)
        // or Algorithm 3.5 (Revision 3 or greater) using the supplied password
        // string
        //
        // I.e., figure out what the general key would be with the
        // given password
        // Algorithm 3.4/5,Step1:
        // Determine general key based on user password, as per Algorithm 3.2
        final byte[] generalKey = calculateGeneralEncryptionKey(
                userPassword, firstDocIdValue, keyBitLength,
                revision, oValue, pValue, encryptMetadata);
        // Algorithm 3.4/5,RemainingSteps:
        final byte[] calculatedUValue =
                calculateUValue(generalKey, firstDocIdValue, revision);

        // Step 2: If the result of step 1 is equal to the value of the
        // encryption dictionaryâs U entry (comparing on the first 16 bytes in
        // the case of Revision 3 or greater), the password supplied is the
        // correct user password. The key obtained in step 1 (that is, in the
        // first step of Algorithm 3.4 or 3.5) can be used to decrypt the
        // document using Algorithm 3.1 on page 119.
        assert calculatedUValue.length == 32;
        if (uValue.length != calculatedUValue.length) {
            throw new PDFParseException("Improper U entry length; " +
                    "expected 32, is " + uValue.length);
        }
        // Only the first 16 bytes are significant if using revision > 2
        final int numSignificantBytes = revision == 2 ? 32 : 16;
        for (int i = 0; i < numSignificantBytes; ++i) {
            if (uValue[i] != calculatedUValue[i]) {
                return null;
            }
        }
        return generalKey;
    }