You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2010/12/02 20:41:14 UTC
svn commit: r1041553 - in
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox: cos/COSName.java
pdmodel/encryption/PDEncryptionDictionary.java
pdmodel/encryption/SecurityHandler.java
pdmodel/encryption/StandardSecurityHandler.java
Author: lehmi
Date: Thu Dec 2 19:41:13 2010
New Revision: 1041553
URL: http://svn.apache.org/viewvc?rev=1041553&view=rev
Log:
PDFBOX-907: added support for encrypted pdfs containing metadata which aren't encrypted as proposed by Martijn Brinkers
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionDictionary.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/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1041553&r1=1041552&r2=1041553&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Thu Dec 2 19:41:13 2010
@@ -382,6 +382,9 @@ public final class COSName extends COSBa
/** "Encrypt" */
public static final COSName ENCRYPT = new COSName( "Encrypt" );
+ /** "EncryptMetaData" */
+ public static final COSName ENCRYPT_META_DATA = new COSName( "EncryptMetadata" );
+
/** "ExtGState" */
public static final COSName EXT_G_STATE = new COSName( "ExtGState" );
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java?rev=1041553&r1=1041552&r2=1041553&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java Thu Dec 2 19:41:13 2010
@@ -20,6 +20,8 @@ package org.apache.pdfbox.pdmodel.encryp
import java.io.IOException;
import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSBoolean;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
@@ -302,6 +304,25 @@ public class PDEncryptionDictionary
}
/**
+ * Will get the EncryptMetaData dictionary info.
+ *
+ * @return true if EncryptMetaData is explicitly set to false (the default is true)
+ */
+ public boolean isEncryptMetaData()
+ {
+ // default is true (see 7.6.3.2 Standard Encryption Dictionary PDF 32000-1:2008)
+ boolean encryptMetaData = true;
+
+ COSBase value = encryptionDictionary.getDictionaryObject(COSName.ENCRYPT_META_DATA);
+
+ if (value instanceof COSBoolean) {
+ encryptMetaData = ((COSBoolean)value).getValue();
+ }
+
+ return encryptMetaData;
+ }
+
+ /**
* This will set the Recipients field of the dictionary. This field contains an array
* of string.
* @param recipients the array of bytes arrays to put in the Recipients field.
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=1041553&r1=1041552&r2=1041553&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 Thu Dec 2 19:41:13 2010
@@ -223,6 +223,10 @@ public abstract class SecurityHandler
public void encryptData(long objectNumber, long genNumber, InputStream data, OutputStream output, boolean decrypt)
throws CryptographyException, IOException
{
+ if (aes && !decrypt) {
+ throw new IllegalArgumentException("AES encryption is not yet implemented.");
+ }
+
byte[] newKey = new byte[ encryptionKey.length + 5 ];
System.arraycopy( encryptionKey, 0, newKey, 0, encryptionKey.length );
//PDF 1.4 reference pg 73
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=1041553&r1=1041552&r2=1041553&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 Thu Dec 2 19:41:13 2010
@@ -180,6 +180,9 @@ public class StandardSecurityHandler ext
documentIDBytes = new byte[0];
}
+ // we need to know whether the meta data was encrypted for password calculation
+ boolean encryptMetadata = dictionary.isEncryptMetaData();
+
byte[] u = dictionary.getUserKey();
byte[] o = dictionary.getOwnerKey();
@@ -191,7 +194,8 @@ public class StandardSecurityHandler ext
dicPermissions,
documentIDBytes,
dicRevision,
- dicLength );
+ dicLength,
+ encryptMetadata);
boolean isOwnerPassword =
isOwnerPassword(
password.getBytes(),
@@ -200,7 +204,8 @@ public class StandardSecurityHandler ext
dicPermissions,
documentIDBytes,
dicRevision,
- dicLength );
+ dicLength,
+ encryptMetadata);
if( isUserPassword )
{
@@ -212,7 +217,8 @@ public class StandardSecurityHandler ext
dicPermissions,
documentIDBytes,
dicRevision,
- dicLength );
+ dicLength,
+ encryptMetadata );
}
else if( isOwnerPassword )
{
@@ -225,7 +231,8 @@ public class StandardSecurityHandler ext
dicPermissions,
documentIDBytes,
dicRevision,
- dicLength );
+ dicLength,
+ encryptMetadata);
}
else
{
@@ -330,10 +337,10 @@ public class StandardSecurityHandler ext
byte[] u = computeUserPassword(
userPassword.getBytes("ISO-8859-1"),
- o, permissionInt, id.getBytes(), revision, length);
+ o, permissionInt, id.getBytes(), revision, length, true);
encryptionKey = computeEncryptedKey(
- userPassword.getBytes("ISO-8859-1"), o, permissionInt, id.getBytes(), revision, length);
+ userPassword.getBytes("ISO-8859-1"), o, permissionInt, id.getBytes(), revision, length, true);
encryptionDictionary.setOwnerKey(o);
encryptionDictionary.setUserKey(u);
@@ -366,11 +373,12 @@ public class StandardSecurityHandler ext
int permissions,
byte[] id,
int encRevision,
- int length)
+ int length,
+ boolean encryptMetadata)
throws CryptographyException, IOException
{
byte[] userPassword = getUserPassword( ownerPassword, o, encRevision, length );
- return isUserPassword( userPassword, u, o, permissions, id, encRevision, length );
+ return isUserPassword( userPassword, u, o, permissions, id, encRevision, length, encryptMetadata );
}
/**
@@ -501,7 +509,8 @@ public class StandardSecurityHandler ext
int permissions,
byte[] id,
int encRevision,
- int length )
+ int length,
+ boolean encryptMetadata)
throws CryptographyException
{
byte[] result = new byte[ length ];
@@ -531,6 +540,15 @@ public class StandardSecurityHandler ext
//step 5
md.update( id );
+
+ //(Security handlers of revision 4 or greater) If document metadata is not being encrypted,
+ //pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
+ //see 7.6.3.3 Algorithm 2 Step f of PDF 32000-1:2008
+ if( encRevision == 4 && !encryptMetadata)
+ {
+ md.update(new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff});
+ }
+
byte[] digest = md.digest();
//step 6
@@ -581,12 +599,13 @@ public class StandardSecurityHandler ext
int permissions,
byte[] id,
int encRevision,
- int length )
+ int length,
+ boolean encryptMetadata)
throws CryptographyException, IOException
{
ByteArrayOutputStream result = new ByteArrayOutputStream();
//STEP 1
- byte[] encryptionKey = computeEncryptedKey( password, o, permissions, id, encRevision, length );
+ byte[] encryptionKey = computeEncryptedKey( password, o, permissions, id, encRevision, length, encryptMetadata );
if( encRevision == 2 )
{
@@ -764,12 +783,14 @@ public class StandardSecurityHandler ext
int permissions,
byte[] id,
int encRevision,
- int length)
+ int length,
+ boolean encryptMetadata)
throws CryptographyException, IOException
{
boolean matches = false;
//STEP 1
- byte[] computedValue = computeUserPassword( password, o, permissions, id, encRevision, length );
+ byte[] computedValue = computeUserPassword( password, o, permissions, id, encRevision, length,
+ encryptMetadata );
if( encRevision == 2 )
{
//STEP 2
@@ -810,11 +831,12 @@ public class StandardSecurityHandler ext
int permissions,
byte[] id,
int encRevision,
- int length)
+ int length,
+ boolean encryptMetadata )
throws CryptographyException, IOException
{
return isUserPassword(password.getBytes(),
- u,o,permissions, id, encRevision, length);
+ u,o,permissions, id, encRevision, length, encryptMetadata);
}
/**
@@ -840,11 +862,12 @@ public class StandardSecurityHandler ext
int permissions,
byte[] id,
int encRevision,
- int length)
+ int length,
+ boolean encryptMetadata)
throws CryptographyException, IOException
{
return isOwnerPassword(password.getBytes(),
- u,o,permissions, id, encRevision, length);
+ u,o,permissions, id, encRevision, length, encryptMetadata);
}
private static final boolean arraysEqual( byte[] first, byte[] second, int count )