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.
*