Attach a patch file that enables certificate encryption for itext-1.4.6.
   
  Sample code to use public key security handler:
   
          Certificate[] recipientCerts = new Certificate[2];
        int[] permissions = new int[2];
 
        Security.addProvider(new BouncyCastleProvider());  
  
        CertificateFactory cf = CertificateFactory.getInstance("X.509");        
                    
        InputStream inStream = new FileInputStream("c:\\temp\\aikensam.cer");
        recipientCerts[0] = (X509Certificate)cf.generateCertificate(inStream);
        inStream.close();  
        
        permissions[0] = PdfWriter.AllowCopy | PdfWriter.AllowPrinting | 
PdfWriter.AllowModifyContents | PdfWriter.AllowScreenReaders
                        | PdfWriter.AllowModifyAnnotations | 
PdfWriter.AllowFillIn | PdfWriter.AllowAssembly | 
PdfWriter.AllowDegradedPrinting;
        
        inStream = new FileInputStream("c:\\temp\\ericchou.cer");
        recipientCerts[1] = (X509Certificate)cf.generateCertificate(inStream);
        inStream.close();          
        permissions[1] = PdfWriter.AllowCopy;
  
        writer.setEncryption(recipientCerts, permissions, 
PdfWriter.STRENGTH128BITS); 

 ___________________________________________________ 
 您的生活即時通 - 溝通、娛樂、生活、工作一次搞定! 
 http://messenger.yahoo.com.tw/
diff -ruN c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfEncryption.java 
com\lowagie\text\pdf\PdfEncryption.java
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfEncryption.java     Sat Sep 
16 22:17:44 2006
+++ com\lowagie\text\pdf\PdfEncryption.java     Wed Nov 22 16:51:53 2006
@@ -50,10 +50,31 @@
 
 package com.lowagie.text.pdf;
 
+import com.lowagie.bc.asn1.DERObject;
+
+import com.lowagie.bc.asn1.DEROutputStream;
+
 import java.security.MessageDigest;
 
 import com.lowagie.text.ExceptionConverter;
 
+import java.io.ByteArrayOutputStream;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.Certificate;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
 /**
  *
  * @author  Paulo Soares ([EMAIL PROTECTED])
@@ -86,6 +107,11 @@
     byte ownerKey[] = new byte[32];
     /** The encryption key for the user */
     byte userKey[] = new byte[32];
+    /** The encryption certificates */
+    protected  PdfPublicKeySecurityHandler publicKeyHandler = null;
+//     handler.add(new PdfPublicKeyRecipient(certificate, permission));
+
+    PdfDictionary publicSecurityDictionary = null;
     int permissions;
     byte documentID[];
     static long seq = System.currentTimeMillis();
@@ -97,6 +123,9 @@
         catch (Exception e) {
             throw new ExceptionConverter(e);
         }
+        publicKeyHandler = new PdfPublicKeySecurityHandler();
+//        mkey = new byte[20];
+//        getEncryptionDictionary();        
     }
 
     public PdfEncryption(PdfEncryption enc) {
@@ -107,6 +136,7 @@
         permissions = enc.permissions;
         if (enc.documentID != null)
             documentID = (byte[])enc.documentID.clone();
+        publicKeyHandler = enc.publicKeyHandler;
     }
 
     /**
@@ -289,6 +319,13 @@
         setupUserKey(revision);
     }
 
+    public void setupByEncryptionKey(byte[] key, int permissions, int 
keylength, int revision) {
+      mkey = new byte[keylength/8];
+      System.arraycopy(key, 0, mkey, 0, mkey.length);
+      //setupUserKey(revision);
+    }
+
+
     public void prepareKey() {
         prepareRC4Key(key, 0, keySize);
     }
@@ -321,20 +358,89 @@
     }
 
     public PdfDictionary getEncryptionDictionary() {
-        PdfDictionary dic = new PdfDictionary();
-        dic.put(PdfName.FILTER, PdfName.STANDARD);
-        dic.put(PdfName.O, new 
PdfLiteral(PdfContentByte.escapeString(ownerKey)));
-        dic.put(PdfName.U, new 
PdfLiteral(PdfContentByte.escapeString(userKey)));
-        dic.put(PdfName.P, new PdfNumber(permissions));
-        if (mkey.length > 5) {
-            dic.put(PdfName.V, new PdfNumber(2));
-            dic.put(PdfName.R, new PdfNumber(3));
-            dic.put(PdfName.LENGTH, new PdfNumber(128));
-        }
-        else {
-            dic.put(PdfName.V, new PdfNumber(1));
-            dic.put(PdfName.R, new PdfNumber(2));
+        PdfDictionary dic = null;
+        
+        if (publicKeyHandler.getRecipientsSize() > 0) {
+            //if (publicSecurityDictionary == null)
+            {
+                dic = new PdfDictionary();
+                publicSecurityDictionary = dic;
+            
+                //mkey = new byte[10];                                        
+                dic.put(PdfName.FILTER, PdfName.PUBSEC);                     
+                dic.put(PdfName.V, new PdfNumber(2));
+                dic.put(PdfName.R, new PdfNumber(3));               
+                dic.put(PdfName.LENGTH, new PdfNumber(128));
+                dic.put(PdfName.SUBFILTER, new PdfName("adbe.pkcs7.s4"));
+
+/*              PdfArray recipients = new PdfArray();
+                byte[] cms = null;
+                try {
+                    cms = 
publicKeyHandler.getEncodedReceipent(publicKeyHandler.getSeed());
+                } catch (GeneralSecurityException e) {
+                   e.printStackTrace();
+                } catch (IOException e) {
+                     e.printStackTrace();
+                }                        
+                recipients.add(new 
PdfLiteral(PdfContentByte.escapeString(cms)));
+*/
+
+                try {
+                    PdfArray recipients = 
publicKeyHandler.getEncodedReceipents();
+                    dic.put(new PdfName("Recipients"), recipients);
+                } catch (IOException f) {
+                    f.printStackTrace();
+                } catch (GeneralSecurityException f) {
+                    f.printStackTrace();
+                } 
+
+                MessageDigest md = null;
+                byte[] encodedRecipient = null;
+
+                try {
+                    md = MessageDigest.getInstance("SHA-1");
+                    md.update(publicKeyHandler.getSeed());            
+                    for (int i=0; i<publicKeyHandler.getRecipientsSize(); i++)
+                    {
+
+                    //PdfLiteral recipient = 
(PdfLiteral)recipients.getArrayList().get(0);
+
+                    //encodedRecipient = 
PdfPublicKeySecurityHandler.unescapedString(recipient.getBytes());
+                    //md.update(encodedRecipient, 1, encodedRecipient.length - 
2);                
+                    /*PdfString recipient = new 
PdfString(publicKeyHandler.getEncodedReceipent(i));
+                    md.update(recipient.getBytes());*/
+                        encodedRecipient = 
publicKeyHandler.getEncodedReceipent(i);
+                        md.update(encodedRecipient);
+                    }
+                } catch (NoSuchAlgorithmException f) {
+                    f.printStackTrace();
+                } catch (IOException f) {
+                    f.printStackTrace();
+                } catch (GeneralSecurityException f) {
+                    f.printStackTrace();
+                } 
+                    
+                byte[] mdResult = md.digest();
+            
+                setupByEncryptionKey(mdResult, 0, 128, 3);  
+            }// else dic = publicSecurityDictionary;
+        } else {        
+            dic = new PdfDictionary();
+            dic.put(PdfName.FILTER, PdfName.STANDARD);
+            dic.put(PdfName.O, new 
PdfLiteral(PdfContentByte.escapeString(ownerKey)));
+            dic.put(PdfName.U, new 
PdfLiteral(PdfContentByte.escapeString(userKey)));
+            dic.put(PdfName.P, new PdfNumber(permissions));
+            if (mkey.length > 5) {
+                dic.put(PdfName.V, new PdfNumber(2));
+                dic.put(PdfName.R, new PdfNumber(3));
+                dic.put(PdfName.LENGTH, new PdfNumber(128));
+            }
+            else {
+                dic.put(PdfName.V, new PdfNumber(1));
+                dic.put(PdfName.R, new PdfNumber(2));
+            }        
         }
+        
         return dic;
     }
 
@@ -387,5 +493,20 @@
     public PdfObject getFileID() {
         return createInfoId(documentID);
     }
+    
+    public void addRecipient(Certificate cert, int permission) {
+        documentID = createDocumentId();
+        publicKeyHandler.addRecipient(new PdfPublicKeyRecipient(cert, 
permission));
+        //getEncryptionDictionary();
+    }
+/*
+    public void setCertificates(Certificate[] certificates) {
+        documentID = createDocumentId();
+        this.certificates = certificates;
+        getEncryptionDictionary();
+    }
 
+    public Certificate[] getCertificates() {
+        return certificates;
+    }*/
 }
diff -ruN c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfEncryption.java.rej 
com\lowagie\text\pdf\PdfEncryption.java.rej
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfEncryption.java.rej Wed Nov 
22 17:09:52 2006
+++ com\lowagie\text\pdf\PdfEncryption.java.rej Thu Jan 01 08:00:00 1970
@@ -1,260 +0,0 @@
-***************
-*** 50,80 ****
-  
-  package com.lowagie.text.pdf;
-  
-- import com.lowagie.bc.asn1.DERObject;
-- 
-- import com.lowagie.bc.asn1.DEROutputStream;
-- 
-  import java.security.MessageDigest;
-  
-  import com.lowagie.text.ExceptionConverter;
-  
-- import java.io.ByteArrayOutputStream;
-- 
-- import java.io.FileNotFoundException;
-- import java.io.FileOutputStream;
-- import java.io.IOException;
-- 
-- import java.security.GeneralSecurityException;
-- import java.security.NoSuchAlgorithmException;
-- import java.security.SecureRandom;
-- import java.security.Security;
-- import java.security.cert.Certificate;
-- 
-- import javax.crypto.KeyGenerator;
-- import javax.crypto.SecretKey;
-- 
-- import org.bouncycastle.jce.provider.BouncyCastleProvider;
-- 
-  /**
-   *
-   * @author  Paulo Soares ([EMAIL PROTECTED])
---- 50,59 ----
-  
-  package com.lowagie.text.pdf;
-  
-  import java.security.MessageDigest;
-  
-  import com.lowagie.text.ExceptionConverter;
-  
-  /**
-   *
-   * @author  Paulo Soares ([EMAIL PROTECTED])
-***************
-*** 107,117 ****
-      byte ownerKey[] = new byte[32];
-      /** The encryption key for the user */
-      byte userKey[] = new byte[32];
--     /** The encryption certificates */
--     protected  PdfPublicKeySecurityHandler publicKeyHandler = null;
-- //     handler.add(new PdfPublicKeyRecipient(certificate, permission));
-- 
--     PdfDictionary publicSecurityDictionary = null;
-      int permissions;
-      byte documentID[];
-      static long seq = System.currentTimeMillis();
---- 86,91 ----
-      byte ownerKey[] = new byte[32];
-      /** The encryption key for the user */
-      byte userKey[] = new byte[32];
-      int permissions;
-      byte documentID[];
-      static long seq = System.currentTimeMillis();
-***************
-*** 123,131 ****
-          catch (Exception e) {
-              throw new ExceptionConverter(e);
-          }
--         publicKeyHandler = new PdfPublicKeySecurityHandler();
-- //        mkey = new byte[20];
-- //        getEncryptionDictionary();        
-      }
-  
-      public PdfEncryption(PdfEncryption enc) {
---- 97,102 ----
-          catch (Exception e) {
-              throw new ExceptionConverter(e);
-          }
-      }
-  
-      public PdfEncryption(PdfEncryption enc) {
-***************
-*** 136,142 ****
-          permissions = enc.permissions;
-          if (enc.documentID != null)
-              documentID = (byte[])enc.documentID.clone();
--         publicKeyHandler = enc.publicKeyHandler;
-      }
-  
-      /**
---- 107,112 ----
-          permissions = enc.permissions;
-          if (enc.documentID != null)
-              documentID = (byte[])enc.documentID.clone();
-      }
-  
-      /**
-***************
-*** 319,331 ****
-          setupUserKey(revision);
-      }
-  
--     public void setupByEncryptionKey(byte[] key, int permissions, int 
keylength, int revision) {
--       mkey = new byte[keylength/8];
--       System.arraycopy(key, 0, mkey, 0, mkey.length);
--       //setupUserKey(revision);
--     }
-- 
-- 
-      public void prepareKey() {
-          prepareRC4Key(key, 0, keySize);
-      }
---- 289,294 ----
-          setupUserKey(revision);
-      }
-  
-      public void prepareKey() {
-          prepareRC4Key(key, 0, keySize);
-      }
-***************
-*** 358,446 ****
-      }
-  
-      public PdfDictionary getEncryptionDictionary() {
--         PdfDictionary dic = null;
--         
--         if (publicKeyHandler.getRecipientsSize() > 0) {
--             //if (publicSecurityDictionary == null)
--             {
--                 dic = new PdfDictionary();
--                 publicSecurityDictionary = dic;
--             
--                 //mkey = new byte[10];                                       
 
--                 dic.put(PdfName.FILTER, PdfName.PUBSEC);                     
--                 dic.put(PdfName.V, new PdfNumber(2));
--                 dic.put(PdfName.R, new PdfNumber(3));               
--                 dic.put(PdfName.LENGTH, new PdfNumber(128));
--                 dic.put(PdfName.SUBFILTER, new PdfName("adbe.pkcs7.s4"));
-- 
-- /*              PdfArray recipients = new PdfArray();
--                 byte[] cms = null;
--                 try {
--                     cms = 
publicKeyHandler.getEncodedReceipent(publicKeyHandler.getSeed());
--                 } catch (GeneralSecurityException e) {
--                    e.printStackTrace();
--                 } catch (IOException e) {
--                      e.printStackTrace();
--                 }                        
--                 recipients.add(new 
PdfLiteral(PdfContentByte.escapeString(cms)));
-- */
-- 
--                 try {
--                     PdfArray recipients = 
publicKeyHandler.getEncodedReceipents();
--                     dic.put(new PdfName("Recipients"), recipients);
--                 } catch (IOException f) {
--                     f.printStackTrace();
--                 } catch (GeneralSecurityException f) {
--                     f.printStackTrace();
--                 } 
-- 
--                 MessageDigest md = null;
--                 byte[] encodedRecipient = null;
-- 
--                 try {
--                     md = MessageDigest.getInstance("SHA-1");
--                     md.update(publicKeyHandler.getSeed());            
--                     for (int i=0; i<publicKeyHandler.getRecipientsSize(); 
i++)
--                     {
-- 
--                     //PdfLiteral recipient = 
(PdfLiteral)recipients.getArrayList().get(0);
-- 
--                     //encodedRecipient = 
PdfPublicKeySecurityHandler.unescapedString(recipient.getBytes());
--                     //md.update(encodedRecipient, 1, encodedRecipient.length 
- 2);                
--                     /*PdfString recipient = new 
PdfString(publicKeyHandler.getEncodedReceipent(i));
--                     md.update(recipient.getBytes());*/
--                         encodedRecipient = 
publicKeyHandler.getEncodedReceipent(i);
--                         md.update(encodedRecipient);
--                     }
--                 } catch (NoSuchAlgorithmException f) {
--                     f.printStackTrace();
--                 } catch (IOException f) {
--                     f.printStackTrace();
--                 } catch (GeneralSecurityException f) {
--                     f.printStackTrace();
--                 } 
--                     
--                 byte[] mdResult = md.digest();
--             
--                 setupByEncryptionKey(mdResult, 0, 128, 3);  
--             }// else dic = publicSecurityDictionary;
--         } else {        
--             dic = new PdfDictionary();
--             dic.put(PdfName.FILTER, PdfName.STANDARD);
--             dic.put(PdfName.O, new 
PdfLiteral(PdfContentByte.escapeString(ownerKey)));
--             dic.put(PdfName.U, new 
PdfLiteral(PdfContentByte.escapeString(userKey)));
--             dic.put(PdfName.P, new PdfNumber(permissions));
--             if (mkey.length > 5) {
--                 dic.put(PdfName.V, new PdfNumber(2));
--                 dic.put(PdfName.R, new PdfNumber(3));
--                 dic.put(PdfName.LENGTH, new PdfNumber(128));
--             }
--             else {
--                 dic.put(PdfName.V, new PdfNumber(1));
--                 dic.put(PdfName.R, new PdfNumber(2));
--             }        
-          }
--         
-          return dic;
-      }
-  
---- 321,340 ----
-      }
-  
-      public PdfDictionary getEncryptionDictionary() {
-+         PdfDictionary dic = new PdfDictionary();
-+         dic.put(PdfName.FILTER, PdfName.STANDARD);
-+         dic.put(PdfName.O, new 
PdfLiteral(PdfContentByte.escapeString(ownerKey)));
-+         dic.put(PdfName.U, new 
PdfLiteral(PdfContentByte.escapeString(userKey)));
-+         dic.put(PdfName.P, new PdfNumber(permissions));
-+         if (mkey.length > 5) {
-+             dic.put(PdfName.V, new PdfNumber(2));
-+             dic.put(PdfName.R, new PdfNumber(3));
-+             dic.put(PdfName.LENGTH, new PdfNumber(128));
-+         }
-+         else {
-+             dic.put(PdfName.V, new PdfNumber(1));
-+             dic.put(PdfName.R, new PdfNumber(2));
-          }
-          return dic;
-      }
-  
-***************
-*** 493,512 ****
-      public PdfObject getFileID() {
-          return createInfoId(documentID);
-      }
--     
--     public void addRecipient(Certificate cert, int permission) {
--         documentID = createDocumentId();
--         publicKeyHandler.addRecipient(new PdfPublicKeyRecipient(cert, 
permission));
--         //getEncryptionDictionary();
--     }
-- /*
--     public void setCertificates(Certificate[] certificates) {
--         documentID = createDocumentId();
--         this.certificates = certificates;
--         getEncryptionDictionary();
--     }
-  
--     public Certificate[] getCertificates() {
--         return certificates;
--     }*/
-  }
---- 387,391 ----
-      public PdfObject getFileID() {
-          return createInfoId(documentID);
-      }
-  
-  }
diff -ruN c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfName.java 
com\lowagie\text\pdf\PdfName.java
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfName.java   Mon Jun 05 
06:23:38 2006
+++ com\lowagie\text\pdf\PdfName.java   Fri Nov 17 16:01:00 2006
@@ -798,6 +798,8 @@
     /** A name */
     public static final PdfName STANDARD = new PdfName("Standard");
     /** A name */
+    public static final PdfName PUBSEC = new PdfName("Adobe.PubSec");
+    /** A name */
     public static final PdfName STATE = new PdfName("State");
     /** A name */
     public static final PdfName STRIKEOUT = new PdfName("StrikeOut");
diff -ruN c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfName.java.rej 
com\lowagie\text\pdf\PdfName.java.rej
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfName.java.rej       Wed Nov 
22 17:09:52 2006
+++ com\lowagie\text\pdf\PdfName.java.rej       Thu Jan 01 08:00:00 1970
@@ -1,17 +0,0 @@
-***************
-*** 798,805 ****
-      /** A name */
-      public static final PdfName STANDARD = new PdfName("Standard");
-      /** A name */
--     public static final PdfName PUBSEC = new PdfName("Adobe.PubSec");
--     /** A name */
-      public static final PdfName STATE = new PdfName("State");
-      /** A name */
-      public static final PdfName STRIKEOUT = new PdfName("StrikeOut");
---- 798,803 ----
-      /** A name */
-      public static final PdfName STANDARD = new PdfName("Standard");
-      /** A name */
-      public static final PdfName STATE = new PdfName("State");
-      /** A name */
-      public static final PdfName STRIKEOUT = new PdfName("StrikeOut");
diff -ruN 
c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfPublicKeyRecipient.java 
com\lowagie\text\pdf\PdfPublicKeyRecipient.java
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfPublicKeyRecipient.java     
Thu Jan 01 08:00:00 1970
+++ com\lowagie\text\pdf\PdfPublicKeyRecipient.java     Wed Nov 22 10:43:37 2006
@@ -0,0 +1,34 @@
+package com.lowagie.text.pdf;
+
+import java.security.cert.Certificate;
+
+public class PdfPublicKeyRecipient {
+
+  private Certificate certificate = null;
+    
+  private int permission = 0;
+  
+  protected byte[] cms = null;
+               
+       public PdfPublicKeyRecipient(Certificate certificate, int permission)
+       {
+               this.certificate = certificate;
+               this.permission = permission;
+       }
+
+    public Certificate getCertificate() {
+        return certificate;
+    }
+
+    public int getPermission() {
+        return permission;
+    }
+
+    protected void setCms(byte[] cms) {
+        this.cms = cms;
+    }
+
+    protected byte[] getCms() {
+        return cms;
+    }
+}
diff -ruN 
c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfPublicKeySecurityHandler.java 
com\lowagie\text\pdf\PdfPublicKeySecurityHandler.java
--- 
c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfPublicKeySecurityHandler.java   
    Thu Jan 01 08:00:00 1970
+++ com\lowagie\text\pdf\PdfPublicKeySecurityHandler.java       Wed Nov 22 
17:05:59 2006
@@ -0,0 +1,278 @@
+/**
+ *     The below 2 methods are from pdfbox.
+ * 
+ *     private DERObject createDERForRecipient(byte[] in, X509Certificate 
cert) ;
+ *     private KeyTransRecipientInfo computeRecipientInfo(X509Certificate 
x509certificate, byte[] abyte0);
+ */
+
+/**
+ * Copyright (c) 2003-2006, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, 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. Neither the name of pdfbox; nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, 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.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+
+
+package com.lowagie.text.pdf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import java.util.ArrayList;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.asn1.cms.EncryptedContentInfo;
+import org.bouncycastle.asn1.cms.EnvelopedData;
+import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
+import org.bouncycastle.asn1.cms.KeyTransRecipientInfo;
+import org.bouncycastle.asn1.cms.RecipientIdentifier;
+import org.bouncycastle.asn1.cms.RecipientInfo;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+
+public class PdfPublicKeySecurityHandler {
+    
+    static final int SEED_LENGTH = 20;
+    //private Certificate[] certificates = null;
+    private ArrayList recipients = null;
+    private byte[] seed = new byte[SEED_LENGTH];
+
+    public PdfPublicKeySecurityHandler() {
+        KeyGenerator key;
+        try {
+            key = KeyGenerator.getInstance("AES");
+            key.init(192, new SecureRandom());
+            SecretKey sk = key.generateKey();            
+            System.arraycopy(sk.getEncoded(), 0, seed, 0, SEED_LENGTH); // 
create the 20 bytes seed            
+        } catch (NoSuchAlgorithmException e) {
+            System.out.println("Debug: " + e.getMessage());
+            seed = SecureRandom.getSeed(SEED_LENGTH); 
+        }
+    
+        recipients = new ArrayList();
+    }
+
+
+    /* 
+     * Routine for decode output of PdfContentByte.escapeString(byte[] bytes).
+     * It should be moved to PdfContentByte.
+     */
+     
+    static public byte[] unescapedString(byte[] bytes) throws 
BadPdfFormatException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+              
+        int index = 0;
+        
+        if (bytes[0] != '(' && bytes[bytes.length-1] != ')') throw new 
BadPdfFormatException("Expect '(' and ')' at begin and end of the string.");
+        
+        while (index < bytes.length) {
+            if (bytes[index] == '\\') {
+                index++;
+                switch (bytes[index]) {
+                case 'b':
+                    baos.write('\b');
+                    break;
+                case 'f':
+                    baos.write('\f');
+                    break;
+                case 't':
+                    baos.write('\t');
+                    break;
+                case 'n':
+                    baos.write('\n');
+                    break;
+                case 'r':
+                    baos.write('\r');
+                    break;
+                case '(':
+                        baos.write('(');
+                        break;
+                case ')':
+                        baos.write(')');
+                        break;                        
+                case '\\':
+                    baos.write('\\');
+                    break;
+                }
+            } else
+                baos.write(bytes[index]);
+            index++;
+        }
+        return baos.toByteArray();
+    }
+    
+    public void addRecipient(PdfPublicKeyRecipient recipient) {
+        recipients.add(recipient);
+    }
+    
+    protected byte[] getSeed() {
+        return (byte[])seed.clone();
+    }
+    /*
+    public PdfPublicKeyRecipient[] getRecipients() {
+        recipients.toArray(); 
+        return (PdfPublicKeyRecipient[])recipients.toArray(); 
+    }*/
+    
+    public int getRecipientsSize() {
+        return recipients.size();
+    }
+    
+    public byte[] getEncodedReceipent(int index) throws IOException, 
GeneralSecurityException {
+        //Certificate certificate = recipient.getX509();
+        PdfPublicKeyRecipient recipient = 
(PdfPublicKeyRecipient)recipients.get(index);
+        byte[] cms = recipient.getCms();
+        
+        if (cms != null) return cms;
+        
+        Certificate certificate  = recipient.getCertificate();
+        int permission =  recipient.getPermission();//PdfWriter.AllowCopy | 
PdfWriter.AllowPrinting | PdfWriter.AllowScreenReaders | 
PdfWriter.AllowAssembly;   
+        int revision = 3;
+        
+        permission |= revision==3 ? 0xfffff0c0 : 0xffffffc0;
+        permission &= 0xfffffffc;
+        permission += 1;
+      
+        byte[] pkcs7input = new byte[24];
+        
+        byte one = (byte)(permission);
+        byte two = (byte)(permission >> 8);
+        byte three = (byte)(permission >> 16);
+        byte four = (byte)(permission >> 24);
+
+        System.arraycopy(seed, 0, pkcs7input, 0, 20); // put this seed in the 
pkcs7 input
+                            
+        pkcs7input[20] = four;
+        pkcs7input[21] = three;                
+        pkcs7input[22] = two;
+        pkcs7input[23] = one;
+
+        DERObject obj = createDERForRecipient(pkcs7input, 
(X509Certificate)certificate);
+            
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            
+        DEROutputStream k = new DEROutputStream(baos);
+            
+        k.writeObject(obj);  
+        
+        cms = baos.toByteArray();
+
+        recipient.setCms(cms);
+        
+        return cms;    
+    }
+    
+    public PdfArray getEncodedReceipents() throws IOException, 
+                                         GeneralSecurityException {
+        PdfArray EncodedRecipients = new PdfArray();
+        byte[] cms = null;
+        for (int i=0; i<recipients.size(); i++)
+        try {
+            cms = getEncodedReceipent(i);
+            EncodedRecipients.add(new 
PdfLiteral(PdfContentByte.escapeString(cms)));
+        } catch (GeneralSecurityException e) {
+            e.printStackTrace();
+            EncodedRecipients = null;
+        } catch (IOException e) {
+            e.printStackTrace();
+            EncodedRecipients = null;
+        }
+        
+        return EncodedRecipients;
+    }
+    
+    private DERObject createDERForRecipient(byte[] in, X509Certificate cert) 
+        throws IOException,  
+               GeneralSecurityException 
+    {
+        
+        String s = "1.2.840.113549.3.2";
+        //String s = "1.2.840.113549.3.7";
+        
+        AlgorithmParameterGenerator algorithmparametergenerator = 
AlgorithmParameterGenerator.getInstance(s);
+        AlgorithmParameters algorithmparameters = 
algorithmparametergenerator.generateParameters();        
+        ByteArrayInputStream bytearrayinputstream = new 
ByteArrayInputStream(algorithmparameters.getEncoded("ASN.1"));
+        ASN1InputStream asn1inputstream = new 
ASN1InputStream(bytearrayinputstream);
+        DERObject derobject = asn1inputstream.readObject();
+        KeyGenerator keygenerator = KeyGenerator.getInstance(s);
+        keygenerator.init(128);
+        SecretKey secretkey = keygenerator.generateKey();
+        Cipher cipher = Cipher.getInstance(s);
+        cipher.init(1, secretkey, algorithmparameters);
+        byte[] abyte1 = cipher.doFinal(in);
+        DEROctetString deroctetstring = new DEROctetString(abyte1);
+        KeyTransRecipientInfo keytransrecipientinfo = 
computeRecipientInfo(cert, secretkey.getEncoded());
+        DERSet derset = new DERSet(new RecipientInfo(keytransrecipientinfo));
+        AlgorithmIdentifier algorithmidentifier = new AlgorithmIdentifier(new 
DERObjectIdentifier(s), derobject);
+        EncryptedContentInfo encryptedcontentinfo = 
+            new EncryptedContentInfo(PKCSObjectIdentifiers.data, 
algorithmidentifier, deroctetstring);
+        EnvelopedData env = new EnvelopedData(null, derset, 
encryptedcontentinfo, null);
+        ContentInfo contentinfo = 
+            new ContentInfo(PKCSObjectIdentifiers.envelopedData, env);
+        return contentinfo.getDERObject();        
+    }
+    
+    private KeyTransRecipientInfo computeRecipientInfo(X509Certificate 
x509certificate, byte[] abyte0)
+        throws GeneralSecurityException, IOException
+    {
+        ASN1InputStream asn1inputstream = 
+            new ASN1InputStream(new 
ByteArrayInputStream(x509certificate.getTBSCertificate()));
+        TBSCertificateStructure tbscertificatestructure = 
+            TBSCertificateStructure.getInstance(asn1inputstream.readObject());
+        AlgorithmIdentifier algorithmidentifier = 
tbscertificatestructure.getSubjectPublicKeyInfo().getAlgorithmId();
+        IssuerAndSerialNumber issuerandserialnumber = 
+            new IssuerAndSerialNumber(
+                tbscertificatestructure.getIssuer(), 
+                tbscertificatestructure.getSerialNumber().getValue());
+        Cipher cipher = 
Cipher.getInstance(algorithmidentifier.getObjectId().getId());        
+        cipher.init(1, x509certificate);
+        DEROctetString deroctetstring = new 
DEROctetString(cipher.doFinal(abyte0));
+        RecipientIdentifier recipId = new 
RecipientIdentifier(issuerandserialnumber);
+        return new KeyTransRecipientInfo( recipId, algorithmidentifier, 
deroctetstring);
+    }
+    
+}
diff -ruN c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfReader.java 
com\lowagie\text\pdf\PdfReader.java
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfReader.java Wed Oct 25 
22:08:40 2006
+++ com\lowagie\text\pdf\PdfReader.java Wed Nov 22 11:58:10 2006
@@ -69,8 +69,21 @@
 import com.lowagie.text.ExceptionConverter;
 import com.lowagie.text.PageSize;
 import com.lowagie.text.Rectangle;
+
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.Certificate;
+
 import java.util.Stack;
 
+import org.bouncycastle.cms.CMSEnvelopedData;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.RecipientInformation;
+
 /** Reads a PDF document.
  * @author Paulo Soares ([EMAIL PROTECTED])
  * @author Kazuya Ujihara
@@ -115,6 +128,9 @@
     protected char pdfVersion;
     protected PdfEncryption decrypt;
     protected byte password[] = null; //added by ujihara for decryption
+    protected Key certificateKey = null; //added by Aiken Sam for certificate 
decryption
+    protected Certificate certificate = null; //added by Aiken Sam for 
certificate decryption
+    protected String certificateKeyProvider = null; //added by Aiken Sam for 
certificate decryption
     protected ArrayList strings = new ArrayList();
     protected boolean sharedStreams = true;
     protected boolean consolidateNamedDestinations = false;
@@ -155,6 +171,19 @@
         tokens = new PRTokeniser(filename);
         readPdf();
     }
+    
+    /** Reads and parses a PDF document.
+     * @param filename the file name of the document
+     * @param ownerPassword the password to read the document
+     * @throws IOException on error
+     */
+    public PdfReader(String filename, Certificate certificate, Key 
certificateKey, String certificateKeyProvider) throws IOException {
+        this.certificate = certificate;
+        this.certificateKey = certificateKey;
+        this.certificateKeyProvider = certificateKeyProvider;
+        tokens = new PRTokeniser(filename);
+        readPdf();
+    }    
 
     /** Reads and parses a PDF document.
      * @param pdfIn the byte array with the document
@@ -543,6 +572,9 @@
      * @throws IOException
      */
     private void readDecryptedDocObj() throws IOException {
+        byte[] encryptionKey = null;
+        
+    
         if (encrypted)
             return;
         PdfObject encDic = trailer.get(PdfName.ENCRYPT);
@@ -561,11 +593,20 @@
             s = o.toString();
             documentID = com.lowagie.text.DocWriter.getISOBytes(s);
         }
-
+        
+        PdfObject filter = getPdfObjectRelease(enc.get(PdfName.FILTER));
+        String securityHandlerName = filter.toString();
+
+        byte uValue[] = null;
+        byte oValue[] = null;
+        int lengthValue = -1;        
+        
+        if (securityHandlerName.equals("/Standard"))
+        {
         s = enc.get(PdfName.U).toString();
-        byte uValue[] = com.lowagie.text.DocWriter.getISOBytes(s);
+        uValue = com.lowagie.text.DocWriter.getISOBytes(s);
         s = enc.get(PdfName.O).toString();
-        byte oValue[] = com.lowagie.text.DocWriter.getISOBytes(s);
+        oValue = com.lowagie.text.DocWriter.getISOBytes(s);
 
         o = enc.get(PdfName.R);
         if (!o.isNumber()) throw new IOException("Illegal R value.");
@@ -577,7 +618,7 @@
         pValue = ((PdfNumber)o).intValue();
 
         // get the Keylength if Revision is 3
-        int lengthValue;
+
         if ( rValue == 3 ){
             o = enc.get(PdfName.LENGTH);
             if (!o.isNumber())
@@ -590,10 +631,80 @@
             lengthValue=40;
         }
 
+        } else if (securityHandlerName.equals("/Adobe.PubSec")) {
+            /*o = enc.get(PdfName.R);
+            if (!o.isNumber()) throw new IOException("Illegal R value.");
+            rValue = ((PdfNumber)o).intValue();
+            if (rValue != 2 && rValue != 3) throw new IOException("Unknown 
encryption type (" + rValue + ")");
+
+            // get the Keylength if Revision is 3
+
+            if ( rValue == 3 ){
+                o = enc.get(PdfName.LENGTH);
+                if (!o.isNumber())
+                  throw new IOException("Illegal Length value.");
+                lengthValue = ( (PdfNumber) o).intValue();
+                if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 
!= 0)
+                  throw new IOException("Illegal Length value.");
+            } else {
+                // Keylength is 40 bit in revision 2
+                lengthValue=40;
+            }*/
+            
+            PdfArray recipients = (PdfArray)enc.get(new PdfName("Recipients"));
+            PdfObject recipient = (PdfObject)recipients.getArrayList().get(0);
+            
+            byte[] myPdfKey = null;
+            CMSEnvelopedData data = null;
+            try {
+                data = new CMSEnvelopedData(recipient.getBytes());
+            } catch (CMSException f) {
+                f.printStackTrace();
+            }
+                
+            Iterator recipCertificatesIt = 
+                data.getRecipientInfos().getRecipients().iterator();
+            boolean foundRecipient = false;
+            
+            while (recipCertificatesIt.hasNext()) {
+                RecipientInformation ri = 
+                    (RecipientInformation)recipCertificatesIt.next();
+                // Impl: if a matching certificate was previously found it is 
an error, 
+                // here we just don't care about it
+
+                if (ri.getRID().match(certificate) && !foundRecipient) {
+                    foundRecipient = true;
+                    try {
+                         myPdfKey = ri.getContent(certificateKey, 
certificateKeyProvider);
+                    } catch (CMSException f) {
+                        f.printStackTrace();
+                    } catch (NoSuchProviderException f) {
+                        f.printStackTrace();
+                    }
+                }
+            }
+
+            MessageDigest md = null;
 
+            try {
+                md = MessageDigest.getInstance("SHA-1");
+            } catch (NoSuchAlgorithmException f) {
+                f.printStackTrace();
+            }
+            md.update(myPdfKey, 0, 20);
+
+            for (int i=0; i<recipients.size(); i++)
+            {
+              byte[] encodedRecipient = 
((PdfObject)recipients.getArrayList().get(i)).getBytes();  
+              md.update(encodedRecipient);
+            }
+            encryptionKey = md.digest();
+        }
 
         decrypt = new PdfEncryption();
 
+        if (securityHandlerName.equals("/Standard"))
+        {
         //check by user password
         decrypt.setupByUserPassword(documentID, password, oValue, pValue, 
lengthValue, rValue);
         if (!equalsArray(uValue, decrypt.userKey, rValue == 3 ? 16 : 32)) {
@@ -603,6 +714,12 @@
                 throw new IOException("Bad user password");
             }
         }
+        
+        } else if (securityHandlerName.equals("/Adobe.PubSec")) {   
+            lengthValue = 128; rValue = 3;
+            decrypt.setupByEncryptionKey(encryptionKey, 0, lengthValue, 
rValue);  
+        }
+        
         for (int k = 0; k < strings.size(); ++k) {
             PdfString str = (PdfString)strings.get(k);
             str.decrypt(this);
diff -ruN c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfWriter.java 
com\lowagie\text\pdf\PdfWriter.java
--- c:\temp\itext-src-1.4.6\com\lowagie\text\pdf\PdfWriter.java Wed Oct 25 
22:08:42 2006
+++ com\lowagie\text\pdf\PdfWriter.java Wed Nov 22 16:58:44 2006
@@ -73,6 +73,8 @@
 import com.lowagie.text.Table;
 import com.lowagie.text.pdf.events.PdfPageEventForwarder;
 
+import java.security.cert.Certificate;
+
 /**
  * A <CODE>DocWriter</CODE> class for PDF.
  * <P>
@@ -1914,6 +1916,22 @@
         crypto = new PdfEncryption();
         crypto.setupAllKeys(userPassword, ownerPassword, permissions, 
strength128Bits);
     }
+    
+    /*
+      By Aiken Sam.
+    */
+     public void setEncryption(Certificate[] certs, int[] permissions, boolean 
strength128Bits) throws DocumentException {
+         if (pdf.isOpen())
+             throw new DocumentException("Encryption can only be added before 
opening the document.");
+         crypto = new PdfEncryption();
+         if (certs != null)
+         for (int i=0; i<certs.length; i++)
+         {
+            crypto.addRecipient(certs[i], permissions[i]);
+         }
+         crypto.getEncryptionDictionary();
+     }
+    
     
     /**
      * Sets the encryption options for this document. The userPassword and the
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
iText-questions mailing list
iText-questions@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/itext-questions
Buy the iText book: http://itext.ugent.be/itext-in-action/

Reply via email to