You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by je...@apache.org on 2003/03/13 17:46:06 UTC
cvs commit: xml-fop/src/java/org/apache/fop/render/pdf PDFRenderer.java
jeremias 2003/03/13 08:46:06
Modified: src/java/org/apache/fop/fo FOUserAgent.java
src/java/org/apache/fop/pdf PDFDocument.java
src/java/org/apache/fop/render/pdf PDFRenderer.java
Added: src/java/org/apache/fop/pdf PDFEncryptionParams.java
PDFEncryptionManager.java PDFEncryptionJCE.java
PDFEncryption.java
Log:
Added support for PDF encryption.
Submitted by: Patrick C. Lankswert <PL...@InsightBB.COM>
Enhanced to be disabled automatically if JCE and/or necessary algorithms are unavailable.
PDF encryption doesn't work, yet. If it's enabled Acrobat will show blank pages. Don't know why, yet. See separate mail.
Revision Changes Path
1.2 +21 -0 xml-fop/src/java/org/apache/fop/fo/FOUserAgent.java
Index: FOUserAgent.java
===================================================================
RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/fo/FOUserAgent.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- FOUserAgent.java 11 Mar 2003 13:05:19 -0000 1.1
+++ FOUserAgent.java 13 Mar 2003 16:46:02 -0000 1.2
@@ -63,6 +63,7 @@
import org.apache.avalon.framework.logger.Logger;
// FOP
+import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.render.XMLHandler;
import org.apache.fop.render.RendererContext;
@@ -92,6 +93,7 @@
private Map defaults = new java.util.HashMap();
private Map handlers = new java.util.HashMap();
private String baseURL;
+ private PDFEncryptionParams pdfEncryptionParams;
/**
* Sets the logger.
@@ -132,6 +134,24 @@
}
/**
+ * Returns the parameters for PDF encryption.
+ * @return the PDF encryption parameters, null if not applicable
+ */
+ public PDFEncryptionParams getPDFEncryptionParams() {
+ return pdfEncryptionParams;
+ }
+
+ /**
+ * Sets the parameters for PDF encryption.
+ * @param pdfEncryptionParams the PDF encryption parameters, null to
+ * disable PDF encryption
+ */
+ public void setPDFEncryptionParams(PDFEncryptionParams pdfEncryptionParams) {
+ this.pdfEncryptionParams = pdfEncryptionParams;
+ }
+
+
+ /**
* Get an input stream for a reference.
* Temporary solution until API better.
* @param uri URI to access
@@ -216,5 +236,6 @@
+ "No handler defined for XML: " + namespace);
}
}
+
}
1.2 +48 -11 xml-fop/src/java/org/apache/fop/pdf/PDFDocument.java
Index: PDFDocument.java
===================================================================
RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/pdf/PDFDocument.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- PDFDocument.java 11 Mar 2003 13:05:09 -0000 1.1
+++ PDFDocument.java 13 Mar 2003 16:46:05 -0000 1.2
@@ -159,6 +159,11 @@
protected PDFResources resources;
/**
+ * the documents encryption, if exists
+ */
+ protected PDFEncryption encryption;
+
+ /**
* the colorspace (0=RGB, 1=CMYK)
*/
protected PDFColorSpace colorspace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
@@ -299,6 +304,30 @@
}
/**
+ * Enables PDF encryption.
+ * @param params The encryption parameters for the pdf file
+ */
+ public void setEncryption(PDFEncryptionParams params) {
+ this.encryption = PDFEncryptionManager.newInstance(++this.objectcount, params);
+ if (encryption != null) {
+ /**@todo this cast is ugly. PDFObject should be transformed to an interface. */
+ addTrailerObject((PDFObject)this.encryption);
+ } else {
+ System.out.println("PDF encryption is unavailable. PDF will be "
+ + "generated without encryption.");
+ }
+ }
+
+
+ /**
+ * Indicates whether encryption is active for this PDF or not.
+ * @return boolean True if encryption is active
+ */
+ public boolean isEncryptionActive() {
+ return this.encryption != null;
+ }
+
+ /**
* Make a /Catalog (Root) object. This object is written in
* the trailer.
*
@@ -1696,7 +1725,7 @@
}
/**
- * make a stream object
+ * Make a stream object
*
* @param type the type of stream to be created
* @param add if true then the stream will be added immediately
@@ -1704,13 +1733,13 @@
*/
public PDFStream makeStream(String type, boolean add) {
- /*
- * create a PDFStream with the next object number and add it
- *
- * to the list of objects
- */
+ // create a PDFStream with the next object number
+ // and add it to the list of objects
PDFStream obj = new PDFStream(++this.objectcount);
obj.addDefaultFilters(filterMap, type);
+ if (isEncryptionActive()) {
+ this.encryption.applyFilter(obj);
+ }
if (add) {
this.objects.add(obj);
@@ -1841,7 +1870,7 @@
* @throws IOException if there is an exception writing to the output stream
*/
public void outputHeader(OutputStream stream)
- throws IOException {
+ throws IOException {
this.position = 0;
byte[] pdf = ("%PDF-" + PDF_VERSION + "\n").getBytes();
@@ -1864,7 +1893,7 @@
* @throws IOException if there is an exception writing to the output stream
*/
public void outputTrailer(OutputStream stream)
- throws IOException {
+ throws IOException {
output(stream);
for (int count = 0; count < trailerObjects.size(); count++) {
PDFObject o = (PDFObject) trailerObjects.get(count);
@@ -1876,13 +1905,21 @@
by the table's length */
this.position += outputXref(stream);
+ // Determine existance of encryption dictionary
+ String encryptEntry = "";
+ if (this.encryption != null) {
+ encryptEntry = this.encryption.getTrailerEntry();
+ }
+
/* construct the trailer */
String pdf = "trailer\n" + "<<\n"
+ "/Size " + (this.objectcount + 1) + "\n"
+ "/Root " + this.root.number + " "
- + this.root.generation + " R\n" + "/Info "
- + this.info.number + " " + this.info.generation
- + " R\n" + ">>\n" + "startxref\n" + this.xref
+ + this.root.generation + " R\n"
+ + "/Info " + this.info.number + " "
+ + this.info.generation + " R\n"
+ + encryptEntry
+ + ">>\n" + "startxref\n" + this.xref
+ "\n" + "%%EOF\n";
/* write the trailer */
1.1 xml-fop/src/java/org/apache/fop/pdf/PDFEncryptionParams.java
Index: PDFEncryptionParams.java
===================================================================
/*
* $Id$
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <jt...@jtauber.com>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.pdf;
/**
* This class holds the parameters for PDF encryption.
*/
public class PDFEncryptionParams {
private String userPassword = ""; //May not be null
private String ownerPassword = ""; //May not be null
private boolean allowPrint = true;
private boolean allowCopyContent = true;
private boolean allowEditContent = true;
private boolean allowEditAnnotations = true;
/**
* Creates a new instance.
* @param userPassword the user password
* @param ownerPassword the owner password
* @param allowPrint true if printing is allowed
* @param allowCopyContent true if copying content is allowed
* @param allowEditContent true if editing content is allowed
* @param allowEditAnnotations true if editing annotations is allowed
*/
public PDFEncryptionParams(String userPassword, String ownerPassword,
boolean allowPrint,
boolean allowCopyContent,
boolean allowEditContent,
boolean allowEditAnnotations) {
setUserPassword(userPassword);
setOwnerPassword(ownerPassword);
setAllowPrint(allowPrint);
setAllowCopyContent(allowCopyContent);
setAllowEditContent(allowEditContent);
setAllowEditAnnotations(allowEditAnnotations);
}
/**
* Default constructor initializing to default values.
*/
public PDFEncryptionParams() {
//nop
}
/**
* Indicates whether copying content is allowed.
* @return true if copying is allowed
*/
public boolean isAllowCopyContent() {
return allowCopyContent;
}
/**
* Indicates whether editing annotations is allowed.
* @return true is editing annotations is allowed
*/
public boolean isAllowEditAnnotations() {
return allowEditAnnotations;
}
/**
* Indicates whether editing content is allowed.
* @return true if editing content is allowed
*/
public boolean isAllowEditContent() {
return allowEditContent;
}
/**
* Indicates whether printing is allowed.
* @return true if printing is allowed
*/
public boolean isAllowPrint() {
return allowPrint;
}
/**
* Returns the owner password.
* @return the owner password, an empty string if no password applies
*/
public String getOwnerPassword() {
return ownerPassword;
}
/**
* Returns the user password.
* @return the user password, an empty string if no password applies
*/
public String getUserPassword() {
return userPassword;
}
/**
* Sets the permission for copying content.
* @param allowCopyContent true if copying content is allowed
*/
public void setAllowCopyContent(boolean allowCopyContent) {
this.allowCopyContent = allowCopyContent;
}
/**
* Sets the permission for editing annotations.
* @param allowEditAnnotations true if editing annotations is allowed
*/
public void setAllowEditAnnotations(boolean allowEditAnnotations) {
this.allowEditAnnotations = allowEditAnnotations;
}
/**
* Sets the permission for editing content.
* @param allowEditContent true if editing annotations is allowed
*/
public void setAllowEditContent(boolean allowEditContent) {
this.allowEditContent = allowEditContent;
}
/**
* Sets the persmission for printing.
* @param allowPrint true if printing is allowed
*/
public void setAllowPrint(boolean allowPrint) {
this.allowPrint = allowPrint;
}
/**
* Sets the owner password.
* @param ownerPassword The owner password to set, null or an empty String
* if no password is applicable
*/
public void setOwnerPassword(String ownerPassword) {
if (ownerPassword == null) {
this.ownerPassword = "";
} else {
this.ownerPassword = ownerPassword;
}
}
/**
* Sets the user password.
* @param userPassword The user password to set, null or an empty String
* if no password is applicable
*/
public void setUserPassword(String userPassword) {
if (userPassword == null) {
this.userPassword = "";
} else {
this.userPassword = userPassword;
}
}
}
1.1 xml-fop/src/java/org/apache/fop/pdf/PDFEncryptionManager.java
Index: PDFEncryptionManager.java
===================================================================
/*
* $Id$
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <jt...@jtauber.com>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.pdf;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Provider;
import java.security.Security;
import org.apache.avalon.framework.logger.Logger;
import org.apache.fop.fo.FOUserAgent;
/**
* This class acts as a factory for PDF encryption support. It enables the
* feature to be optional to FOP depending on the availability of JCE.
*/
public class PDFEncryptionManager {
/**
* Indicates whether JCE is available.
* @return boolean true if JCE is present
*/
public static boolean isJCEAvailable() {
try {
Class clazz = Class.forName("javax.crypto.Cipher");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
/**
* Checks whether the necessary algorithms are available.
* @return boolean True if all necessary algorithms are present
*/
public static boolean checkAvailableAlgorithms() {
if (!isJCEAvailable()) {
return false;
} else {
Provider[] providers;
providers = Security.getProviders("Cipher.RC4");
if (providers == null) {
return false;
}
providers = Security.getProviders("MessageDigest.MD5");
if (providers == null) {
return false;
}
return true;
}
}
/**
* Sets up PDF encryption if PDF encryption is requested by registering
* a <code>PDFEncryptionParams</code> object with the user agent and if
* the necessary cryptographic support is available.
* @param userAgent the user agent
* @param pdf the PDF document to setup encryption for
* @param log the logger to send warnings to
*/
public static void setupPDFEncryption(FOUserAgent userAgent,
PDFDocument pdf,
Logger log) {
if (userAgent == null) {
throw new NullPointerException("User agent must not be null");
}
if (pdf == null) {
throw new NullPointerException("PDF document must not be null");
}
if (userAgent.getPDFEncryptionParams() != null) {
if (!checkAvailableAlgorithms()) {
if (isJCEAvailable()) {
log.warn("PDF encryption has been requested, JCE is "
+ "available but there's no "
+ "JCE provider available that provides the "
+ "necessary algorithms. The PDF won't be "
+ "encrypted.");
} else {
log.warn("PDF encryption has been requested but JCE is "
+ "unavailable! The PDF won't be encrypted.");
}
}
pdf.setEncryption(userAgent.getPDFEncryptionParams());
}
}
/**
* Creates a new PDFEncryption instance if PDF encryption is available.
* @param objnum PDF object number
* @param params PDF encryption parameters
* @return PDFEncryption the newly created instance, null if PDF encryption
* is unavailable.
*/
public static PDFEncryption newInstance(int objnum, PDFEncryptionParams params) {
try {
Class clazz = Class.forName("org.apache.fop.pdf.PDFEncryptionJCE");
Method makeMethod = clazz.getMethod("make",
new Class[] {int.class, PDFEncryptionParams.class});
Object obj = makeMethod.invoke(null,
new Object[] {new Integer(objnum), params});
return (PDFEncryption)obj;
} catch (ClassNotFoundException e) {
if (checkAvailableAlgorithms()) {
System.out.println("JCE and algorithms available, but the "
+ "implementation class unavailable. Please do a full "
+ "rebuild.");
}
return null;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}
1.1 xml-fop/src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
Index: PDFEncryptionJCE.java
===================================================================
/*
* $Id: PDFEncryptionJCE.java,v 1.1.2.1 2003/03/05 18:58:15 pietsch Exp $
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <jt...@jtauber.com>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.pdf;
// Java
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;
import java.util.Random;
/**
* class representing a /Filter /Standard object.
*
*/
public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
private class EncryptionFilter extends PDFFilter {
private PDFEncryptionJCE encryption;
private int number;
private int generation;
/**
* The constructor for the internal PDFEncryptionJCE filter
* @param encryption The encryption object to use
* @param number The number of the object to be encrypted
* @param generation The generation of the object to be encrypted
*/
public EncryptionFilter(PDFEncryptionJCE encryption,
int number, int generation) {
super();
this.encryption = encryption;
this.number = number;
this.generation = generation;
}
/**
* Return a PDF string representation of the filter. In this
* case no filter name is passed.
* @return The filter name, blank in this case
*/
public String getName() {
return "";
}
/**
* Return a parameter dictionary for this filter, or null
* @return The parameter dictionary. In this case, null.
*/
public String getDecodeParms() {
return null;
}
/**
* Encode the given data with the filter
* @param data The data to be encrypted
* @return The encrypted data
*/
public byte[] encode(byte[] data) {
return encryption.encryptData(data, number, generation);
}
/**
* @see org.apache.fop.pdf.PDFFilter#encode(InputStream, OutputStream, int)
*/
public void encode(InputStream in, OutputStream out, int length)
throws IOException {
byte[] buffer = new byte[length];
in.read(buffer);
buffer = encode(buffer);
out.write(buffer);
}
}
private static final char [] PAD =
{ 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A };
private static final char[] DIGITS =
{'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/** Value of PRINT permission */
public static final int PERMISSION_PRINT = 4;
/** Value of content editting permission */
public static final int PERMISSION_EDIT_CONTENT = 8;
/** Value of content extraction permission */
public static final int PERMISSION_COPY_CONTENT = 16;
/** Value of annotation editting permission */
public static final int PERMISSION_EDIT_ANNOTATIONS = 32;
// Encryption tools
private MessageDigest digest = null;
private Cipher cipher = null;
private Random random = new Random();
// Control attributes
private PDFEncryptionParams params;
// Output attributes
private byte[] fileID = null;
private byte[] encryptionKey = null;
private String dictionary = null;
/**
* create a /Filter /Standard object.
*
* @param number the object's number
*/
public PDFEncryptionJCE(int number) {
/* generic creation of object */
super(number);
try {
digest = MessageDigest.getInstance("MD5");
cipher = Cipher.getInstance("RC4");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e.getMessage());
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException(e.getMessage());
}
}
/**
* Local factory method.
* @param objnum PDF object number for the encryption object
* @param params PDF encryption parameters
* @return PDFEncryption the newly created PDFEncryption object
*/
public static PDFEncryption make(int objnum, PDFEncryptionParams params) {
PDFEncryptionJCE impl = new PDFEncryptionJCE(objnum);
impl.setParams(params);
impl.init();
return impl;
}
/**
* Returns the encryption parameters.
* @return the encryption parameters
*/
public PDFEncryptionParams getParams() {
return this.params;
}
/**
* Sets the encryption parameters.
* @param params The parameterss to set
*/
public void setParams(PDFEncryptionParams params) {
this.params = params;
}
// Internal procedures
private byte[] prepPassword(String password) {
byte[] obuffer = new byte[32];
byte[] pbuffer = password.getBytes();
int i = 0;
int j = 0;
while (i < obuffer.length && i < pbuffer.length) {
obuffer[i] = pbuffer[i];
i++;
}
while (i < obuffer.length) {
obuffer[i++] = (byte) PAD[j++];
}
return obuffer;
}
private String toHex(byte[] value) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < value.length; i++) {
buffer.append(DIGITS[(value[i] >>> 4) & 0x0F]);
buffer.append(DIGITS[value[i] & 0x0F]);
}
return buffer.toString();
}
/**
* Returns the document file ID
* @return The file ID
*/
public byte[] getFileID() {
if (fileID == null) {
fileID = new byte[16];
random.nextBytes(fileID);
}
return fileID;
}
/**
* This method returns the indexed file ID
* @param index The index to access the file ID
* @return The file ID
*/
public String getFileID(int index) {
if (index == 1) {
return toHex(getFileID());
}
byte[] id = new byte[16];
random.nextBytes(id);
return toHex(id);
}
private byte[] encryptWithKey(byte[] data, byte[] key) {
try {
SecretKeySpec keyspec = new SecretKeySpec(key, "RC4");
cipher.init(Cipher.ENCRYPT_MODE, keyspec);
return cipher.doFinal(data);
} catch (IllegalBlockSizeException e) {
throw new IllegalStateException(e.getMessage());
} catch (BadPaddingException e) {
throw new IllegalStateException(e.getMessage());
} catch (InvalidKeyException e) {
throw new IllegalStateException(e.getMessage());
}
}
private byte[] encryptWithHash(byte[] data, byte[] hash, int size) {
hash = digest.digest(hash);
byte[] key = new byte[size];
for (int i = 0; i < size; i++) {
key[i] = hash[i];
}
return encryptWithKey(data, key);
}
/**
* This method initializes the encryption algorithms and values
*/
public void init() {
// Generate the owner value
byte[] oValue;
if (params.getOwnerPassword().length() > 0) {
oValue = encryptWithHash(
prepPassword(params.getUserPassword()),
prepPassword(params.getOwnerPassword()), 5);
} else {
oValue = encryptWithHash(
prepPassword(params.getUserPassword()),
prepPassword(params.getUserPassword()), 5);
}
// Generate permissions value
int permissions = -4;
if (!params.isAllowPrint()) {
permissions -= PERMISSION_PRINT;
}
if (!params.isAllowCopyContent()) {
permissions -= PERMISSION_COPY_CONTENT;
}
if (!params.isAllowEditContent()) {
permissions -= PERMISSION_EDIT_CONTENT;
}
if (!params.isAllowEditAnnotations()) {
permissions -= PERMISSION_EDIT_ANNOTATIONS;
}
// Create the encrption key
digest.update(prepPassword(params.getUserPassword()));
digest.update(oValue);
digest.update((byte) (permissions >>> 0));
digest.update((byte) (permissions >>> 8));
digest.update((byte) (permissions >>> 16));
digest.update((byte) (permissions >>> 24));
digest.update(getFileID());
byte [] hash = digest.digest();
this.encryptionKey = new byte[5];
for (int i = 0; i < 5; i++) {
this.encryptionKey[i] = hash[i];
}
// Create the user value
byte[] uValue = encryptWithKey(prepPassword(""), this.encryptionKey);
// Create the dictionary
this.dictionary = this.number + " " + this.generation
+ " obj\n<< /Filter /Standard\n"
+ "/V 1\n"
+ "/R 2\n"
+ "/Length 40\n"
+ "/P " + permissions + "\n"
+ "/O <" + toHex(oValue) + ">\n"
+ "/U <" + toHex(uValue) + ">\n"
+ ">>\n"
+ "endobj\n";
}
/**
* This method encrypts the passed data using the generated keys.
* @param data The data to be encrypted
* @param number The block number
* @param generation The block generation
* @return The encrypted data
*/
public byte[] encryptData(byte[] data, int number, int generation) {
if (this.encryptionKey == null) {
throw new IllegalStateException("PDF Encryption has not been initialized");
}
byte[] hash = new byte[this.encryptionKey.length + 5];
int i = 0;
while (i < this.encryptionKey.length) {
hash[i] = this.encryptionKey[i]; i++;
}
hash[i++] = (byte) (number >>> 0);
hash[i++] = (byte) (number >>> 8);
hash[i++] = (byte) (number >>> 16);
hash[i++] = (byte) (generation >>> 0);
hash[i++] = (byte) (generation >>> 8);;
return encryptWithHash(data, hash, hash.length);
}
/**
* Creates PDFFilter for the encryption object
* @param number The object number
* @param generation The objects generation
* @return The resulting filter
*/
public PDFFilter makeFilter(int number, int generation) {
return new EncryptionFilter(this, number, generation);
}
/**
* Adds a PDFFilter to the PDFStream object
* @param stream the stream to add an encryption filter to
*/
public void applyFilter(PDFStream stream) {
stream.addFilter(this.makeFilter(stream.number, stream.generation));
}
/**
* Represent the object in PDF
*
* @return the PDF
*/
public byte[] toPDF() {
if (this.dictionary == null) {
throw new IllegalStateException("PDF Encryption has not been initialized");
}
try {
return this.dictionary.getBytes(PDFDocument.ENCODING);
} catch (UnsupportedEncodingException ue) {
return this.dictionary.getBytes();
}
}
/**
* @see org.apache.fop.pdf.PDFEncryption#getTrailerEntry()
*/
public String getTrailerEntry() {
return "/Encrypt " + number + " "
+ generation + " R\n"
+ "/ID[<" + getFileID(1) + "><"
+ getFileID(2) + ">]\n";
}
}
1.1 xml-fop/src/java/org/apache/fop/pdf/PDFEncryption.java
Index: PDFEncryption.java
===================================================================
/*
* $Id$
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <jt...@jtauber.com>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.pdf;
/**
* This interface defines the contract for classes implementing PDF encryption.
*/
public interface PDFEncryption {
/**
* Returns the encryption parameters.
* @return the encryption parameters
*/
PDFEncryptionParams getParams();
/**
* Sets the encryption parameters.
* @param params The parameterss to set
*/
void setParams(PDFEncryptionParams params);
/**
* Adds a PDFFilter to the PDFStream object
* @param stream the stream to add an encryption filter to
*/
void applyFilter(PDFStream stream);
/**
* Returns the trailer entry for encryption.
* @return the trailer entry
*/
String getTrailerEntry();
}
1.2 +8 -1 xml-fop/src/java/org/apache/fop/render/pdf/PDFRenderer.java
Index: PDFRenderer.java
===================================================================
RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/pdf/PDFRenderer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- PDFRenderer.java 11 Mar 2003 13:05:13 -0000 1.1
+++ PDFRenderer.java 13 Mar 2003 16:46:05 -0000 1.2
@@ -79,6 +79,7 @@
import org.apache.fop.fo.properties.BackgroundRepeat;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFInfo;
@@ -240,6 +241,7 @@
* @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
*/
public void configure(Configuration conf) throws ConfigurationException {
+ //PDF filters
Configuration filters = conf.getChild("filterList");
Configuration[] filt = filters.getChildren("value");
List filterList = new java.util.ArrayList();
@@ -250,6 +252,7 @@
filterMap.put(PDFStream.DEFAULT_FILTER, filterList);
+ //Font configuration
Configuration[] font = conf.getChildren("font");
for (int i = 0; i < font.length; i++) {
Configuration[] triple = font[i].getChildren("font-triplet");
@@ -271,6 +274,7 @@
fontList.add(efi);
}
+
}
/**
@@ -311,7 +315,10 @@
this.pdfDoc = new PDFDocument(producer);
this.pdfDoc.setCreator(creator);
this.pdfDoc.setFilterMap(filterMap);
- pdfDoc.outputHeader(stream);
+ this.pdfDoc.outputHeader(stream);
+
+ //Setup encryption if necessary
+ PDFEncryptionManager.setupPDFEncryption(userAgent, this.pdfDoc, getLogger());
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: fop-cvs-help@xml.apache.org