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 <[EMAIL PROTECTED]> 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) { + /[EMAIL PROTECTED] 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 * [EMAIL PROTECTED] * * 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 <[EMAIL PROTECTED]>. 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 * [EMAIL PROTECTED] * * 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 <[EMAIL PROTECTED]>. 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 * [EMAIL PROTECTED] * * 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 <[EMAIL PROTECTED]>. 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 * [EMAIL PROTECTED] * * 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 <[EMAIL PROTECTED]>. 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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]