You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by tb...@apache.org on 2012/04/07 00:06:48 UTC
svn commit: r1310605 - in
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption:
PublicKeySecurityHandler.java SecurityHandler.java
StandardSecurityHandler.java
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.
*