]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
PDF Encryption works now in every case I tested. Also, the text and string dictionary...
authorJeremias Maerki <jeremias@apache.org>
Thu, 27 Mar 2003 11:10:33 +0000 (11:10 +0000)
committerJeremias Maerki <jeremias@apache.org>
Thu, 27 Mar 2003 11:10:33 +0000 (11:10 +0000)
Bring back support for encrypting byte arrays.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196171 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/pdf/PDFEncryption.java
src/java/org/apache/fop/pdf/PDFEncryptionJCE.java

index e0ad295520ed754993d6ced54a1e953028a70c46..82402090cae6d90084ae15656264b0bde4358564 100644 (file)
@@ -71,7 +71,16 @@ public interface PDFEncryption {
      * Adds a PDFFilter to the PDFStream object
      * @param stream the stream to add an encryption filter to
      */    
-    void applyFilter(PDFStream stream);
+    void applyFilter(AbstractPDFStream stream);
+    /**
+     * Encrypt an array of bytes using a reference PDFObject for calculating
+     * the encryption key.
+     * @param data data to encrypt
+     * @param refObj reference PDFObject
+     * @return byte[] the encrypted data
+     */
+    byte[] encrypt(byte[] data, PDFObject refObj);
  
     /**
      * Returns the trailer entry for encryption.
index affcc2f68c397117cd67248804a78a234bf786a6..954ca2801f63a4230a4232270b05ed69b3a7d49d 100644 (file)
@@ -54,12 +54,12 @@ package org.apache.fop.pdf;
 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.CipherOutputStream;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.BadPaddingException;
 import javax.crypto.NoSuchPaddingException;
@@ -89,6 +89,8 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
             this.encryption = encryption;
             this.number  = number;
             this.generation = generation;
+            //System.out.println("new encryption filter for number "
+            //    +number+" and generation "+generation);
         }
 
         /** 
@@ -128,6 +130,14 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
             out.write(buffer);
         }
         
+        /**
+         * @see org.apache.fop.pdf.PDFFilter#applyFilter(OutputStream)
+         */
+        public OutputStream applyFilter(OutputStream out) throws IOException {
+            return new CipherOutputStream(out, 
+                    encryption.initCipher(number, generation));
+        }
+
     }
 
     private static final char [] PAD = 
@@ -135,9 +145,6 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
                                  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;
@@ -150,7 +157,7 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
     
     // Encryption tools
     private MessageDigest digest = null;
-    private Cipher cipher = null;
+    //private Cipher cipher = null;
     private Random random = new Random();
     // Control attributes
     private PDFEncryptionParams params;
@@ -160,20 +167,21 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
     private String dictionary = null;
 
     /**
-     * create a /Filter /Standard object.
+     * Create a /Filter /Standard object.
      *
-     * @param number the object's number
+     * @param objnum the object's number
      */
-    public PDFEncryptionJCE(int number) {
+    public PDFEncryptionJCE(int objnum) {
         /* generic creation of object */
-        super(number);
+        super();
+        setObjectNumber(objnum);
         try {
             digest = MessageDigest.getInstance("MD5");
-            cipher = Cipher.getInstance("RC4");
+            //cipher = Cipher.getInstance("RC4");
         } catch (NoSuchAlgorithmException e) {
             throw new UnsupportedOperationException(e.getMessage());
-        } catch (NoSuchPaddingException e) {
-            throw new UnsupportedOperationException(e.getMessage());
+        /*} catch (NoSuchPaddingException e) {
+            throw new UnsupportedOperationException(e.getMessage());*/
         }
     }
 
@@ -227,17 +235,6 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
         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
@@ -258,38 +255,63 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
      */    
     public String getFileID(int index) {
         if (index == 1) {
-            return toHex(getFileID());
+            return PDFText.toHex(getFileID());
         }
         
         byte[] id = new byte[16];
         random.nextBytes(id);
-        return toHex(id);
+        return PDFText.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);
+            final Cipher c = initCipher(key);
+            return c.doFinal(data);
         } catch (IllegalBlockSizeException e) {
             throw new IllegalStateException(e.getMessage());
         } catch (BadPaddingException e) {
             throw new IllegalStateException(e.getMessage());
+        }
+    }
+    
+    private Cipher initCipher(byte[] key) {
+        try {
+            Cipher c = Cipher.getInstance("RC4");
+            SecretKeySpec keyspec = new SecretKeySpec(key, "RC4");
+            c.init(Cipher.ENCRYPT_MODE, keyspec);
+            return c;
         } catch (InvalidKeyException e) {
             throw new IllegalStateException(e.getMessage());
+        } catch (NoSuchAlgorithmException e) {
+            throw new UnsupportedOperationException(e.getMessage());
+        } catch (NoSuchPaddingException e) {
+            throw new UnsupportedOperationException(e.getMessage());
         }
     }
     
+    private Cipher initCipher(int number, int generation) {
+        byte[] hash = calcHash(number, generation);
+        int size = hash.length;
+        hash = digest.digest(hash);
+        byte[] key = calcKey(hash, size);
+        return initCipher(key);
+    }
+    
     private byte[] encryptWithHash(byte[] data, byte[] hash, int size) {
         hash = digest.digest(hash);
+
+        byte[] key = calcKey(hash, size);        
         
+        return encryptWithKey(data, key);
+    }
+
+    private byte[] calcKey(byte[] hash, int size) {
         byte[] key = new byte[size];
 
         for (int i = 0; i < size; i++) {
             key[i] = hash[i];
         }
-        
-        return encryptWithKey(data, key);
+        return key;
     }
 
     /** 
@@ -344,14 +366,14 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
         byte[] uValue = encryptWithKey(prepPassword(""), this.encryptionKey);
         
         // Create the dictionary
-        this.dictionary = this.number + " " + this.generation
-                        + " obj\n<< /Filter /Standard\n"
+        this.dictionary = getObjectID() 
+                        + "<< /Filter /Standard\n"
                         + "/V 1\n"
                         + "/R 2\n"
                         + "/Length 40\n"
                         + "/P "  + permissions + "\n"
-                        + "/O <" + toHex(oValue) + ">\n"
-                        + "/U <" + toHex(uValue) + ">\n"
+                        + "/O " + PDFText.toHex(oValue) + "\n"
+                        + "/U " + PDFText.toHex(uValue) + "\n"
                         + ">>\n"
                         + "endobj\n";
     }
@@ -367,11 +389,23 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
         if (this.encryptionKey == null) {
             throw new IllegalStateException("PDF Encryption has not been initialized");
         }
-        
+        //getDocument().getLogger().debug("encrypting with for "+number+" "+generation);
+
+        byte[] hash = calcHash(number, generation);        
+        return encryptWithHash(data, hash, hash.length);
+    }
+
+    /**
+     * @see org.apache.fop.pdf.PDFEncryption#encrypt(byte[], PDFObject)
+     */
+    public byte[] encrypt(byte[] data, PDFObject refObj) {
+        return encryptData(data, refObj.getObjectNumber(), refObj.getGeneration());
+    }
+
+    private byte[] calcHash(int number, int generation) {
         byte[] hash = new byte[this.encryptionKey.length + 5];
             
         int i = 0;
-            
         while (i < this.encryptionKey.length) {
             hash[i] = this.encryptionKey[i]; i++;
         }
@@ -381,8 +415,7 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
         hash[i++] = (byte) (number >>> 16);
         hash[i++] = (byte) (generation >>> 0);
         hash[i++] = (byte) (generation >>> 8);;
-        
-        return encryptWithHash(data, hash, hash.length);
+        return hash;        
     }
 
     /** 
@@ -399,8 +432,9 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
      * 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));
+    public void applyFilter(AbstractPDFStream stream) {
+        stream.getFilterList().addFilter(
+                this.makeFilter(stream.getObjectNumber(), stream.getGeneration()));
     }
     
     /**
@@ -413,20 +447,15 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
             throw new IllegalStateException("PDF Encryption has not been initialized");
         }
         
-        try {
-            return this.dictionary.getBytes(PDFDocument.ENCODING);
-        } catch (UnsupportedEncodingException ue) {
-            return this.dictionary.getBytes();
-        }       
+        return encode(this.dictionary);
     }
 
     /**
      * @see org.apache.fop.pdf.PDFEncryption#getTrailerEntry()
      */
     public String getTrailerEntry() {
-        return "/Encrypt " + number + " " 
-                    + generation + " R\n"
-                    + "/ID[<" + getFileID(1) + "><"
-                    + getFileID(2) + ">]\n";
+        return "/Encrypt " + getObjectNumber() + " " 
+                    + getGeneration() + " R\n"
+                    + "/ID[" + getFileID(1) + getFileID(2) + "]\n";
     }
 }