Author: tboehme
Date: Fri Apr  6 22:06:48 2012
New Revision: 1310605

URL: http://svn.apache.org/viewvc?rev=1310605&view=rev
Log:
second change-set from PDFBOX-1199; moved decryption initialization into 
prepareForDecryption method which allows decryption of single objects

Modified:
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java?rev=1310605&r1=1310604&r2=1310605&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java
 Fri Apr  6 22:06:48 2012
@@ -56,6 +56,7 @@ import org.bouncycastle.cms.CMSEnveloped
 import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.RecipientInformation;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSString;
 import org.apache.pdfbox.exceptions.CryptographyException;
 import org.apache.pdfbox.pdmodel.PDDocument;
@@ -117,118 +118,137 @@ public class PublicKeySecurityHandler ex
 
         PDEncryptionDictionary dictionary = doc.getEncryptionDictionary();
 
-        if(dictionary.getLength() != 0)
-        {
-            this.keyLength = dictionary.getLength();
-        }
-
-        if(!(decryptionMaterial instanceof PublicKeyDecryptionMaterial))
-        {
-            throw new CryptographyException(
-                "Provided decryption material is not compatible with the 
document");
-        }
-
-        PublicKeyDecryptionMaterial material = 
(PublicKeyDecryptionMaterial)decryptionMaterial;
-
-        try
-        {
-            boolean foundRecipient = false;
-
-            // the decrypted content of the enveloped data that match
-            // the certificate in the decryption material provided
-            byte[] envelopedData = null;
-
-            // the bytes of each recipient in the recipients array
-            byte[][] recipientFieldsBytes = new 
byte[dictionary.getRecipientsLength()][];
-
-            int recipientFieldsLength = 0;
-
-            for(int i=0; i<dictionary.getRecipientsLength(); i++)
-            {
-                COSString recipientFieldString = 
dictionary.getRecipientStringAt(i);
-                byte[] recipientBytes = recipientFieldString.getBytes();
-                CMSEnvelopedData data = new CMSEnvelopedData(recipientBytes);
-                Iterator recipCertificatesIt = 
data.getRecipientInfos().getRecipients().iterator();
-                while(recipCertificatesIt.hasNext())
-                {
-                    RecipientInformation ri =
-                        (RecipientInformation)recipCertificatesIt.next();
-                    // Impl: if a matching certificate was previously found it 
is an error,
-                    // here we just don't care about it
-                    if(ri.getRID().match(material.getCertificate()) && 
!foundRecipient)
-                    {
-                        foundRecipient = true;
-                        envelopedData = 
ri.getContent(material.getPrivateKey(), "BC");
-                    }
-                }
-                recipientFieldsBytes[i] = recipientBytes;
-                recipientFieldsLength += recipientBytes.length;
-            }
-            if(!foundRecipient || envelopedData == null)
-            {
-                throw new CryptographyException("The certificate matches no 
recipient entry");
-            }
-            if(envelopedData.length != 24)
-            {
-                throw new CryptographyException("The enveloped data does not 
contain 24 bytes");
-            }
-            // now envelopedData contains:
-            // - the 20 bytes seed
-            // - the 4 bytes of permission for the current user
-
-            byte[] accessBytes = new byte[4];
-            System.arraycopy(envelopedData, 20, accessBytes, 0, 4);
-
-            currentAccessPermission = new AccessPermission(accessBytes);
-            currentAccessPermission.setReadOnly();
-
-             // what we will put in the SHA1 = the seed + each byte contained 
in the recipients array
-            byte[] sha1Input = new byte[recipientFieldsLength + 20];
-
-            // put the seed in the sha1 input
-            System.arraycopy(envelopedData, 0, sha1Input, 0, 20);
-
-            // put each bytes of the recipients array in the sha1 input
-            int sha1InputOffset = 20;
-            for(int i=0; i<recipientFieldsBytes.length; i++)
-            {
-                System.arraycopy(
-                    recipientFieldsBytes[i], 0,
-                    sha1Input, sha1InputOffset, 
recipientFieldsBytes[i].length);
-                sha1InputOffset += recipientFieldsBytes[i].length;
-            }
-
-            MessageDigest md = MessageDigest.getInstance("SHA-1");
-            byte[] mdResult = md.digest(sha1Input);
-
-            // we have the encryption key ...
-            encryptionKey = new byte[this.keyLength/8];
-            System.arraycopy(mdResult, 0, encryptionKey, 0, this.keyLength/8);
-
-            proceedDecryption();
-
-
-        }
-        catch(CMSException e)
-        {
-            throw new CryptographyException(e);
-        }
-        catch(KeyStoreException e)
-        {
-            throw new CryptographyException(e);
-        }
-        catch(NoSuchProviderException e)
-        {
-            throw new CryptographyException(e);
-        }
-        catch(NoSuchAlgorithmException e)
-        {
-            throw new CryptographyException(e);
-        }
-
+        prepareForDecryption( dictionary, doc.getDocument().getDocumentID(),
+                                                                               
                decryptionMaterial );
+        
+        proceedDecryption();
     }
 
     /**
+     * Prepares everything to decrypt the document.
+     *
+     * If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, 
this method is
+     * called from there. Only if decryption of single objects is needed this 
should be called instead.
+     *
+     * @param encDictionary  encryption dictionary, can be retrieved via 
{@link PDDocument#getEncryptionDictionary()}
+     * @param documentIDArray  document id which is returned via {@link 
COSDocument#getDocumentID()} (not used by this handler)
+     * @param decryptionMaterial Information used to decrypt the document.
+     *
+     * @throws IOException If there is an error accessing data.
+     * @throws CryptographyException If there is an error with decryption.
+     */
+    public void prepareForDecryption(PDEncryptionDictionary encDictionary, 
COSArray documentIDArray,
+                                                                               
                                                                 
DecryptionMaterial decryptionMaterial)
+    throws CryptographyException, IOException
+    {
+       
+             if(encDictionary.getLength() != 0)
+             {
+                 this.keyLength = encDictionary.getLength();
+             }
+       
+             if(!(decryptionMaterial instanceof PublicKeyDecryptionMaterial))
+             {
+                 throw new CryptographyException(
+                     "Provided decryption material is not compatible with the 
document");
+             }
+       
+             PublicKeyDecryptionMaterial material = 
(PublicKeyDecryptionMaterial)decryptionMaterial;
+       
+             try
+             {
+                 boolean foundRecipient = false;
+       
+                 // the decrypted content of the enveloped data that match
+                 // the certificate in the decryption material provided
+                 byte[] envelopedData = null;
+       
+                 // the bytes of each recipient in the recipients array
+                 byte[][] recipientFieldsBytes = new 
byte[encDictionary.getRecipientsLength()][];
+       
+                 int recipientFieldsLength = 0;
+       
+                 for(int i=0; i<encDictionary.getRecipientsLength(); i++)
+                 {
+                     COSString recipientFieldString = 
encDictionary.getRecipientStringAt(i);
+                     byte[] recipientBytes = recipientFieldString.getBytes();
+                     CMSEnvelopedData data = new 
CMSEnvelopedData(recipientBytes);
+                     Iterator recipCertificatesIt = 
data.getRecipientInfos().getRecipients().iterator();
+                     while(recipCertificatesIt.hasNext())
+                     {
+                         RecipientInformation ri =
+                             (RecipientInformation)recipCertificatesIt.next();
+                         // Impl: if a matching certificate was previously 
found it is an error,
+                         // here we just don't care about it
+                         if(ri.getRID().match(material.getCertificate()) && 
!foundRecipient)
+                         {
+                             foundRecipient = true;
+                             envelopedData = 
ri.getContent(material.getPrivateKey(), "BC");
+                         }
+                     }
+                     recipientFieldsBytes[i] = recipientBytes;
+                     recipientFieldsLength += recipientBytes.length;
+                 }
+                 if(!foundRecipient || envelopedData == null)
+                 {
+                     throw new CryptographyException("The certificate matches 
no recipient entry");
+                 }
+                 if(envelopedData.length != 24)
+                 {
+                     throw new CryptographyException("The enveloped data does 
not contain 24 bytes");
+                 }
+                 // now envelopedData contains:
+                 // - the 20 bytes seed
+                 // - the 4 bytes of permission for the current user
+       
+                 byte[] accessBytes = new byte[4];
+                 System.arraycopy(envelopedData, 20, accessBytes, 0, 4);
+       
+                 currentAccessPermission = new AccessPermission(accessBytes);
+                 currentAccessPermission.setReadOnly();
+       
+                  // what we will put in the SHA1 = the seed + each byte 
contained in the recipients array
+                 byte[] sha1Input = new byte[recipientFieldsLength + 20];
+       
+                 // put the seed in the sha1 input
+                 System.arraycopy(envelopedData, 0, sha1Input, 0, 20);
+       
+                 // put each bytes of the recipients array in the sha1 input
+                 int sha1InputOffset = 20;
+                 for(int i=0; i<recipientFieldsBytes.length; i++)
+                 {
+                     System.arraycopy(
+                         recipientFieldsBytes[i], 0,
+                         sha1Input, sha1InputOffset, 
recipientFieldsBytes[i].length);
+                     sha1InputOffset += recipientFieldsBytes[i].length;
+                 }
+       
+                 MessageDigest md = MessageDigest.getInstance("SHA-1");
+                 byte[] mdResult = md.digest(sha1Input);
+       
+                 // we have the encryption key ...
+                 encryptionKey = new byte[this.keyLength/8];
+                 System.arraycopy(mdResult, 0, encryptionKey, 0, 
this.keyLength/8);
+             }
+             catch(CMSException e)
+             {
+                 throw new CryptographyException(e);
+             }
+             catch(KeyStoreException e)
+             {
+                 throw new CryptographyException(e);
+             }
+             catch(NoSuchProviderException e)
+             {
+                 throw new CryptographyException(e);
+             }
+             catch(NoSuchAlgorithmException e)
+             {
+                 throw new CryptographyException(e);
+             }
+    }
+    
+    /**
      * Prepare the document for encryption.
      *
      * @param doc The document that will be encrypted.

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java?rev=1310605&r1=1310604&r2=1310605&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
 Fri Apr  6 22:06:48 2012
@@ -42,6 +42,7 @@ import javax.crypto.spec.SecretKeySpec;
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSDocument;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSObject;
 import org.apache.pdfbox.cos.COSStream;
@@ -128,6 +129,23 @@ public abstract class SecurityHandler
     public abstract void prepareDocumentForEncryption(PDDocument doc) throws 
CryptographyException, IOException;
 
     /**
+     * Prepares everything to decrypt the document.
+     * 
+     * If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, 
this method is
+     * called from there. Only if decryption of single objects is needed this 
should be called instead.
+     *
+     * @param encDictionary  encryption dictionary, can be retrieved via 
{@link PDDocument#getEncryptionDictionary()}
+     * @param documentIDArray  document id which is returned via {@link 
COSDocument#getDocumentID()}
+     * @param decryptionMaterial Information used to decrypt the document.
+     *
+     * @throws IOException If there is an error accessing data.
+     * @throws CryptographyException If there is an error with decryption.
+     */
+    public abstract void prepareForDecryption(PDEncryptionDictionary 
encDictionary, COSArray documentIDArray,
+                                                                               
                                                                                
        DecryptionMaterial decryptionMaterial)
+    throws CryptographyException, IOException;
+    
+    /**
      * Prepare the document for decryption.
      *
      * @param doc The document to decrypt.

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java?rev=1310605&r1=1310604&r2=1310605&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
 Fri Apr  6 22:06:48 2012
@@ -149,6 +149,30 @@ public class StandardSecurityHandler ext
         document = doc;
 
         PDEncryptionDictionary dictionary = document.getEncryptionDictionary();
+        COSArray documentIDArray = document.getDocument().getDocumentID();
+        
+        prepareForDecryption(dictionary, documentIDArray, decryptionMaterial);
+        
+        this.proceedDecryption();
+    }
+
+    /**
+     * Prepares everything to decrypt the document.
+     *
+     * If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, 
this method is
+     * called from there. Only if decryption of single objects is needed this 
should be called instead.
+     *
+     * @param encDictionary  encryption dictionary, can be retrieved via 
{@link PDDocument#getEncryptionDictionary()}
+     * @param documentIDArray  document id which is returned via {@link 
COSDocument#getDocumentID()}
+     * @param decryptionMaterial Information used to decrypt the document.
+     *
+     * @throws IOException If there is an error accessing data.
+     * @throws CryptographyException If there is an error with decryption.
+     */
+    public void prepareForDecryption(PDEncryptionDictionary encDictionary, 
COSArray documentIDArray,
+                                                                               
                                                 DecryptionMaterial 
decryptionMaterial)
+        throws CryptographyException, IOException
+    {
         if(!(decryptionMaterial instanceof StandardDecryptionMaterial))
         {
             throw new CryptographyException("Provided decryption material is 
not compatible with the document");
@@ -162,13 +186,12 @@ public class StandardSecurityHandler ext
             password = "";
         }
 
-        int dicPermissions = dictionary.getPermissions();
-        int dicRevision = dictionary.getRevision();
-        int dicLength = dictionary.getLength()/8;
+        int dicPermissions = encDictionary.getPermissions();
+        int dicRevision = encDictionary.getRevision();
+        int dicLength = encDictionary.getLength()/8;
 
         //some documents may have not document id, see
         //test\encryption\encrypted_doc_no_id.pdf
-        COSArray documentIDArray = document.getDocument().getDocumentID();
         byte[] documentIDBytes = null;
         if( documentIDArray != null && documentIDArray.size() >= 1 )
         {
@@ -181,10 +204,10 @@ public class StandardSecurityHandler ext
         }
 
         // we need to know whether the meta data was encrypted for password 
calculation
-        boolean encryptMetadata = dictionary.isEncryptMetaData();
+        boolean encryptMetadata = encDictionary.isEncryptMetaData();
         
-        byte[] u = dictionary.getUserKey();
-        byte[] o = dictionary.getOwnerKey();
+        byte[] u = encDictionary.getUserKey();
+        byte[] o = encDictionary.getOwnerKey();
 
         boolean isUserPassword =
             isUserPassword(
@@ -242,8 +265,7 @@ public class StandardSecurityHandler ext
 
         // detect whether AES encryption is used. This assumes that the 
encryption algo is 
         // stored in the PDCryptFilterDictionary
-        PDCryptFilterDictionary stdCryptFilterDictionary =  
doc.getEncryptionDictionary().
-                getStdCryptFilterDictionary();
+        PDCryptFilterDictionary stdCryptFilterDictionary =  
encDictionary.getStdCryptFilterDictionary();
 
         if (stdCryptFilterDictionary != null)
         {
@@ -253,10 +275,8 @@ public class StandardSecurityHandler ext
                 setAES("AESV2".equalsIgnoreCase(cryptFilterMethod.getName()));
             }
         }
-        
-        this.proceedDecryption();
     }
-
+    
     /**
      * Prepare document for encryption.
      *


Reply via email to