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/