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;
private Map defaults = new java.util.HashMap();
private Map handlers = new java.util.HashMap();
private String baseURL;
+ private PDFEncryptionParams pdfEncryptionParams;
/**
* Sets the logger.
}
}
+ /**
+ * 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.
+ "No handler defined for XML: " + namespace);
}
}
+
}
*/
protected PDFResources resources;
+ /**
+ * the documents encryption, if exists
+ */
+ protected PDFEncryption encryption;
+
/**
* the colorspace (0=RGB, 1=CMYK)
*/
return filterMap;
}
+ /**
+ * 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.
}
/**
- * 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
*/
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);
* @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();
* @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);
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 */
--- /dev/null
+/*
+ * $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 <jtauber@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();
+}
--- /dev/null
+/*
+ * $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 <jtauber@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";
+ }
+}
--- /dev/null
+/*
+ * $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 <jtauber@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;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * $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 <jtauber@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;
+ }
+ }
+
+}
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;
* @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();
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");
fontList.add(efi);
}
+
}
/**
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());
}
/**