You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2014/11/15 17:23:36 UTC

svn commit: r1639903 - /pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java

Author: tilman
Date: Sat Nov 15 16:23:35 2014
New Revision: 1639903

URL: http://svn.apache.org/r1639903
Log:
PDFBOX-2456: DRY refactor of steps (a) to (d) of the algorithm 3 Computing the encryption dictionary O (owner password) value

Modified:
    pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java

Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java?rev=1639903&r1=1639902&r2=1639903&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java Sat Nov 15 16:23:35 2014
@@ -422,41 +422,20 @@ public class StandardSecurityHandler ext
             byte[] ownerPassword,
             byte[] o,
             int encRevision,
-            long length )
+            int length )
             throws CryptographyException, IOException
     {
         try
         {
             ByteArrayOutputStream result = new ByteArrayOutputStream();
+            byte[] rc4Key = computeRC4key(ownerPassword, encRevision, length);
 
-            //3.3 STEP 1
-            byte[] ownerPadded = truncateOrPad( ownerPassword );
-
-            //3.3 STEP 2
-            MessageDigest md = MessageDigest.getInstance( "MD5" );
-            md.update( ownerPadded );
-            byte[] digest = md.digest();
-
-            //3.3 STEP 3
-            if( encRevision == 3 || encRevision == 4 )
-            {
-                for( int i=0; i<50; i++ )
-                {
-                    md.reset();
-                    md.update( digest, 0, (int) length );
-                    digest = md.digest();
-                }
-            }
             if( encRevision == 2 && length != 5 )
             {
                 throw new CryptographyException(
                     "Error: Expected length=5 actual=" + length );
             }
 
-            //3.3 STEP 4
-            byte[] rc4Key = new byte[ (int)length ];
-            System.arraycopy( digest, 0, rc4Key, 0, (int)length );
-
             //3.7 step 2
             if( encRevision == 2 )
             {
@@ -682,34 +661,8 @@ public class StandardSecurityHandler ext
         {
             try
             {
-                //STEP 1
-                byte[] ownerPadded = truncateOrPad( ownerPassword );
-
-                //STEP 2
-                MessageDigest md = MessageDigest.getInstance( "MD5" );
-                md.update( ownerPadded );
-                byte[] digest = md.digest();
-
-                //STEP 3
-                if( encRevision == 3 || encRevision == 4)
-                {
-                    for( int i=0; i<50; i++ )
-                    {
-                        md.reset();
-                        md.update( digest, 0, length );
-                        digest = md.digest();
-                    }
-                }
-                if( encRevision == 2 && length != 5 )
-                {
-                    throw new CryptographyException(
-                        "Error: Expected length=5 actual=" + length );
-                }
-
-                //STEP 4
-                byte[] rc4Key = new byte[ length ];
-                System.arraycopy( digest, 0, rc4Key, 0, length );
-
+                byte[] rc4Key = computeRC4key(ownerPassword, encRevision, length);
+                
                 //STEP 5
                 byte[] paddedUser = truncateOrPad( userPassword );
 
@@ -747,6 +700,43 @@ public class StandardSecurityHandler ext
             }
         }
 
+    // steps (a) to (d) of "Algorithm 3: Computing the encryption dictionary's O (owner password) value".
+    private byte[] computeRC4key(byte[] ownerPassword, int encRevision, int length)
+            throws NoSuchAlgorithmException, CryptographyException
+    {
+        if (encRevision == 2 && length != 5)
+        {
+            throw new CryptographyException(
+                    "Error: Expected length=5 actual=" + length);
+        }
+
+        //3.3 STEP a
+        byte[] ownerPadded = truncateOrPad(ownerPassword);
+
+        //3.3 STEP b
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update(ownerPadded);
+        byte[] digest = md.digest();
+
+        //3.3 STEP c
+        if (encRevision == 3 || encRevision == 4)
+        {
+            for (int i = 0; i < 50; i++)
+            {
+                // this deviates from the spec - however, omitting the length
+                // parameter prevents the file to be opened in Adobe Reader
+                // with the owner password when the key length is 40 bit (= 5 bytes)
+                md.reset();
+                md.update(digest, 0, length);
+                digest = md.digest();
+            }
+        }
+
+        //3.3 STEP d
+        byte[] rc4Key = new byte[(int) length];
+        System.arraycopy(digest, 0, rc4Key, 0, (int) length);
+        return rc4Key;
+    }
 
     /**
      * This will take the password and truncate or pad it as necessary.