I am dynamically creating a PDF document, add a signature field and afterwards trying to sign it. The signing works properly, but i am getting an exception:
"certfied by %, invalid signature and signature contains invalid data"
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Calendar;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
//Actual class
public class SignPdf {
// Signs the pdf
public void signPdf(String src, String dest, boolean certified, boolean graphic) throws GeneralSecurityException, IOException, DocumentException{
String path = "src/certs.pfx";
String keystore_password = "pwd";
String key_password = "pwd";
KeyStore ks = KeyStore.getInstance("PKCS12", new org.bouncycastle.jce.provider.BouncyCastleProvider());
InputStream is = this.getClass().getResourceAsStream("/certs.pfx");
ks.load(is, keystore_password.toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
byte[] pdfByteArray = null;
// creating dynamic document using itext.
Document document = new Document();
OutputStream baosPDF = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baosPDF);
document.open();
document.add(new Paragraph("Hello World!"));
document.close();
byte[] bytearrayb = ((ByteArrayOutputStream) baosPDF).toByteArray();
PdfReader reader = new PdfReader(bytearrayb);
PdfStamper stamper = PdfStamper.createSignature(reader, baosPDF, '\0', null, true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason("Security");
appearance.setLocation("Footer");
appearance.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, "DVA");
if (certified) appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
if (graphic) {
appearance.setSignatureGraphic(Image.getInstance(RESOURCE));
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
}
appearance.setSignDate(Calendar.getInstance());
appearance.setSignatureCreator("test");
ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);
baosPDF.flush();
baosPDF.close();
BufferedOutputStream fs = new BufferedOutputStream(new FileOutputStream(new File("myFile121.pdf")));
fs.write(((ByteArrayOutputStream) baosPDF).toByteArray());
fs.flush();
fs.close();
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
SignPdf signatures = new SignPdf();
try {
signatures.signPdf(ORIGINAL, "", true, false);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
You re-use the ByteArrayOutputStream without clearing it:
OutputStream baosPDF = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baosPDF);
document.open();
document.add(new Paragraph("Hello World!"));
document.close();
byte[] bytearrayb = ((ByteArrayOutputStream) baosPDF).toByteArray();
PdfReader reader = new PdfReader(bytearrayb);
PdfStamper stamper = PdfStamper.createSignature(reader, baosPDF, '\0', null, true);
According to the ByteArrayOutputStream source:
/**
* Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* #see java.io.ByteArrayInputStream#count
*/
public synchronized void reset()
Thus, reset before re-use:
byte[] bytearrayb = ((ByteArrayOutputStream) baosPDF).toByteArray();
baosPDF.reset();
PdfReader reader = new PdfReader(bytearrayb);
PdfStamper stamper = PdfStamper.createSignature(reader, baosPDF, '\0', null, true);
Related
I try convert docx to pdf.
Docx file has korean
maybe you think BTS song's lyrics
Eg.
Friends
BTS
유난히도 반짝였던 서울!
처음 보는 또 다른 세상
땀에 잔뜩 밴 채 만난 넌
뭔가 이상했었던 아이
난 달에서, 넌 별에서
우리 대화는 숙제 같았지
하루는 베프, 하루는 웬수
I just wanna understand
Hello my alien
우린 서로의 mystery
그래서 더 특별한 걸까
언젠가 이 함성 멎을 때 stay, hey
내 옆에 함께 있어줘
영원히 계속 이곳에 stay, hey
네 작은 새끼손가락처럼
일곱 번의 여름과 추운 겨울보다
오래
수많은 약속과 추억들보다
this is my convering code.
String k=null;
OutputStream fileForPdf =null;
try {
String fileName=w;
//Below Code is for .doc file
if(fileName.endsWith(".doc"))
{
HWPFDocument doc = new HWPFDocument(new FileInputStream(
fileName));
WordExtractor we=new WordExtractor(doc);
k = we.getText();
fileForPdf = new FileOutputStream(new File(
p));
we.close();
}
//Below Code for
else if(fileName.endsWith(".docx"))
{
XWPFDocument docx = new XWPFDocument(new FileInputStream(
fileName));
// using XWPFWordExtractor Class
XWPFWordExtractor we = new XWPFWordExtractor(docx);
k = we.getText();
fileForPdf = new FileOutputStream(new File(p));
we.close();
}
Document document = new Document();
PdfWriter.getInstance(document, fileForPdf);
document.open();
document.add(new Paragraph(k));
document.close();
fileForPdf.close();
this code make pdf file But this file didn't have korea lyrics
You can try the following approach to convert a .docx file to .pdf file.
https://simplesolution.dev/java-convert-docx-file-to-pdf-file-using-xdocreport/
import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter;
import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileConverter {
public void convertWordToPdf(String docxFileName, String pdfFileName) {
try(InputStream inputStream = new FileInputStream(docxFileName);
OutputStream outputStream = new FileOutputStream(pdfFileName)) {
XWPFDocument document = new XWPFDocument(inputStream);
PdfOptions options = PdfOptions.create();
// Convert .docx file to .pdf file
PdfConverter.getInstance().convert(document, outputStream, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String docxFileName = "D:\\SimpleSolution\\Data\\Document.docx";
String pdfFileName = "D:\\SimpleSolution\\Data\\Document.pdf";
FileConverter fileConverter = new FileConverter();
fileConverter.convertWordToPdf(docxFileName, pdfFileName);
I am doing a project where i need to sign a pdf using a usb based digital signature. I have tried the following code locally and able to sign the pdf. my problem is weather the following code will work in a client server based senerio.
My code is:
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfSignatureAppearance;
import com.lowagie.text.pdf.PdfStamper;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CRL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import javax.servlet.RequestDispatcher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.mscapi.SunMSCAPI;
public class Testing {
private static boolean resFlag;
public static void main (String args[])
{
try {
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
SunMSCAPI providerMSCAPI = new SunMSCAPI();
Security.addProvider(providerMSCAPI);
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey)ks.getKey(alias, null);
Certificate[] chain = ks.getCertificateChain(alias);
// //String e = request.getParameter("digiFile");
// KeyStore ks = KeyStore.getInstance("pkcs12");
// String f10 = CommonUtil.getRealPath();
// String str8 = f10 + "/DigiFiles/";
// //System.out.println("str8-->>>>>>>>" + str8 + e);
// ks.load(new FileInputStream("F:/DigiFiles/Anurag Goel.pfx"), "123".toCharArray());
//
//
// System.out.println("The actual path is " + str8);
// String alias = (String)ks.aliases().nextElement();
// PrivateKey key = (PrivateKey)ks.getKey(alias, "123".toCharArray());
// Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader("F:/test.pdf");
FileOutputStream os = new FileOutputStream("F:/SampleOutPut61.pdf");
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0',null,true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setCrypto(pk, chain, (CRL[])null, PdfSignatureAppearance.VERISIGN_SIGNED);
appearance.setReason("elicense project");
appearance.setLocation("Assam");
appearance.setVisibleSignature("hi");
stamper.close();
} catch (KeyStoreException var27) {
var27.printStackTrace();
resFlag = false;
} catch (NoSuchAlgorithmException var28) {
var28.printStackTrace();
resFlag = false;
} catch (CertificateException var29) {
var29.printStackTrace();
resFlag = false;
} catch (FileNotFoundException var30) {
var30.printStackTrace();
resFlag = false;
} catch (IOException var31) {
var31.printStackTrace();
resFlag = false;
} catch (UnrecoverableKeyException var32) {
var32.printStackTrace();
resFlag = false;
} catch (DocumentException var33) {
var33.printStackTrace();
resFlag = false;
} catch (Exception var34) {
var34.printStackTrace();
resFlag = false;
} finally {
RequestDispatcher rd;
}
}
}
Please give me suggestion . thanks all
You are using the wrong iText version, hence you are creating signatures that are not future proof (please read this book to find out what's wrong with your code).
You are depending on the fact that the operating system is Windows. Is your server also a Windows server? Your code won't work if it's a Linux server. Check with your hosting provider and also ask your hosting provider if it is allowed for you to have a USB token on that server (if it's not a dedicated server, chances are they are going to refuse that).
You are using Windows-MY which means that you delegate the authentication to the operating system. If the USB needs a passphrase (they usually do), Windows will open up a dialog box for you to fill out that passphrase. If you deploy this on a server: will you have somebody sitting next to that server to fill out that password every time somebody requests a signature?
USB tokens are designed for people to sign a document manually. They usually have specific limitations. For instance: normally, you can not apply more than 1 signature per second. This is usually insufficient in a web context. In a web context, you are expected to use install a Hardware Security Module (HSM) on your server.
While your code may work on a server in theory, I see a lot of reasons why it's not a wise decision to use the code that works on a standalone machine in a client/server environment. There are too many practical issues (such as authentication, speed, wrong version of iText,...) that can make your project go wrong. I would answer "no" to your question whether that code will work in a client/server scenario.
Update:
In your comments to my answer, you indicate that your server is a Linux server. It should be obvious that using "Windows-MY" will never work on a Linux server. You'll have to use PKCS#11 instead of Windows-MY to talk to the hardware device on which your token is stored. This is a code sample that works on a Luna SA from SafeNet. As you can see, it uses PKCS#11:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.pkcs11.SunPKCS11;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.log.SysoLogger;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CertificateUtil;
import com.itextpdf.text.pdf.security.CrlClient;
import com.itextpdf.text.pdf.security.CrlClientOnline;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.TSAClient;
import com.itextpdf.text.pdf.security.TSAClientBouncyCastle;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
public class C4_01_SignWithPKCS11HSM {
public static final String SRC = "/home/itext/hello.pdf";
public static final String PROPS = "/home/itext/key.properties";
public static final String DEST = "/home/itext/hello_hsm.pdf";
public void sign(String src, String dest,
Certificate[] chain, PrivateKey pk,
String digestAlgorithm, String provider, CryptoStandard subfilter,
String reason, String location,
Collection<CrlClient> crlList,
OcspClient ocspClient,
TSAClient tsaClient,
int estimatedSize)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
LoggerFactory.getInstance().setLogger(new SysoLogger());
Properties properties = new Properties();
properties.load(new FileInputStream(PROPS));
char[] pass = properties.getProperty("PASSWORD").toCharArray();
String pkcs11cfg = properties.getProperty("PKCS11CFG");
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
FileInputStream fis = new FileInputStream(pkcs11cfg);
Provider providerPKCS11 = new SunPKCS11(fis);
Security.addProvider(providerPKCS11);
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, pass);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey)ks.getKey(alias, pass);
Certificate[] chain = ks.getCertificateChain(alias);
OcspClient ocspClient = new OcspClientBouncyCastle();
TSAClient tsaClient = null;
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = (X509Certificate)chain[i];
String tsaUrl = CertificateUtil.getTSAURL(cert);
if (tsaUrl != null) {
tsaClient = new TSAClientBouncyCastle(tsaUrl);
break;
}
}
List<CrlClient> crlList = new ArrayList<CrlClient>();
crlList.add(new CrlClientOnline(chain));
C4_01_SignWithPKCS11HSM app = new C4_01_SignWithPKCS11HSM();
app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA256, providerPKCS11.getName(), CryptoStandard.CMS,
"HSM test", "Ghent", crlList, ocspClient, tsaClient, 0);
}
}
The content of the config file that is used looks like this:
Name = Luna
library = /usr/lunasa/lib/libCryptoki2_64.so
slot = 1
Note that the so may be in another directory in your case, and your certificate may be in another slot. I also use a properties file to store the password for the certificate. Obviously I won't share my password ;-)
This example was tested on a server owned by GlobalSign using a GlobalSign certificate.
I'm struggling with with BM25Similarity class in Lucene (link). All examples provided on the Web refers to older implementation (link). I kindly ask for a pointer how to modify the standard toy example below to include BM25 similarity (create index and perform search).
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import java.io.IOException;
public class HelloLucene {
public static void main(String[] args) throws IOException, ParseException {
// Specify the analyzer for tokenizing text.
// The same analyzer should be used for indexing and searching
StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_4_9);
// Create the index
Directory index = new RAMDirectory();
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
IndexWriter w = new IndexWriter(index, config);
addDoc(w, "Lucene in Action", "193398817");
addDoc(w, "Lucene for Dummies", "55320055Z");
addDoc(w, "Managing Gigabytes", "55063554A");
addDoc(w, "The Art of Computer Science", "9900333X");
w.close();
// Query
String querystr = args.length > 0 ? args[0] : "lucene";
// the "title" arg specifies the default field to use
// when no field is explicitly specified in the query.
Query q = new QueryParser(Version.LUCENE_4_9, "title", analyzer).parse(querystr);
// Search
int hitsPerPage = 10;
IndexReader reader = DirectoryReader.open(index);
IndexSearcher searcher = new IndexSearcher(reader);
TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, true);
searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
// Display results
System.out.println("Found " + hits.length + " hits.");
for(int i=0;i<hits.length;++i) {
int docId = hits[i].doc;
Document d = searcher.doc(docId);
System.out.println((i + 1) + ". " + d.get("isbn") + "\t" + d.get("title"));
}
reader.close();
}
private static void addDoc(IndexWriter w, String title, String isbn) throws IOException {
Document doc = new Document();
doc.add(new TextField("title", title, Field.Store.YES));
// use a string field for isbn because we don't want it tokenized
doc.add(new StringField("isbn", isbn, Field.Store.YES));
w.addDocument(doc);
}
}
You just need to set the similarity in IndexSearcher:
searcher.setSimilarity(new BM25Similarity(1.2, 0.75));
And IndexWriterConfig:
config.setSimilarity(new BM25Similarity(1.2, 0.75));
When I am adding digital signature to the encrypted(password protected) PDF using PDF BOX am getting the following exceptions,
Exception in thread "main" java.lang.NullPointerException
at org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler.computeRevisionNumber(StandardSecurityHandler.java:128)
at org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler.prepareDocumentForEncryption(StandardSecurityHandler.java:299)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1457)
at org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1396)
at com.seind.pdf.digitalsignature.CreateVisibleSignature.signPDF(CreateVisibleSignature.java:187)
at com.seind.pdf.digitalsignature.CreateVisibleSignature.main(CreateVisibleSignature.java:305)
But when I am using owner password to decrypt the PDF, its not working. its correct a password which I was used to encrypt... I hope you all understand the problem and here is my sample code:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSSignedGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* This is an example for visual signing a pdf with bouncy castle.
* {#see CreateSignature}
* #author Vakhtang Koroghlishvili
*/
public class CreateVisibleSignature implements SignatureInterface
{
public static final String RESOURCE ="stock1.jpg";//"Paul_Cézanne_222.jpg";//"signature-stamp.jpg";//"SJG_Signature.png";//"amber-signature.png";// "Man-Utd-v-Bayern-Munich-018.jpg";//"check_256.png";//"signature-stamp.jpg";
private static BouncyCastleProvider provider = new BouncyCastleProvider();
private PrivateKey privKey;
private Certificate[] cert;
private SignatureOptions options;
public CreateVisibleSignature()
{
}
/**
* Initialize the signature creator with a keystore (pkcs12) and pin that
* should be used for the signature.
*
* #param keystore is a pkcs12 keystore.
* #param pin is the pin for the keystore / private key
*/
public CreateVisibleSignature(KeyStore keystore, char[] pin)
{
try
{
// grabs the first alias from the keystore and get the private key. An
// alternative method or constructor could be used for setting a specific
// alias that should be used.
Enumeration<String> aliases = keystore.aliases();
String alias = null;
while (aliases.hasMoreElements())
{
alias = aliases.nextElement();
System.out.println(" alias name "+alias);
}
privKey = (PrivateKey) keystore.getKey(alias, pin);
cert = keystore.getCertificateChain(alias);
}
catch (KeyStoreException e)
{
e.printStackTrace();
}
catch (UnrecoverableKeyException e)
{
System.err.println("Could not extract private key.");
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
System.err.println("Unknown algorithm.");
e.printStackTrace();
}
}
/**
* Signs the given pdf file.
*
* #param document is the pdf document
* #param signatureProperties
* #return the signed pdf document
* #throws Exception
*/
public File signPDF(File document, PDVisibleSigProperties signatureProperties) throws Exception
{
PDDocument doc = openPDFDoc(document);
byte[] buffer = new byte[8 * 1024];
if (document == null || !document.exists())
{
new RuntimeException("Document for signing does not exist");
}
// creating output document and prepare the IO streams.
String name = document.getName();
String substring = name.substring(0, name.lastIndexOf("."));
File outputDocument = new File(document.getParent(), substring + "_signed.pdf");
FileInputStream fis = new FileInputStream(document);
FileOutputStream fos = new FileOutputStream(outputDocument);
int c;
while ((c = fis.read(buffer)) != -1)
{
fos.write(buffer, 0, c);
}
fis.close();
fis = new FileInputStream(outputDocument);
// load document
// PDDocument doc = PDDocument.load(document);
// create signature dictionary
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
// subfilter for basic and PAdES Part 2 signatures
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName(signatureProperties.getSignerName());
signature.setLocation("chennai");
//signature.setReason("reason for signature");
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// register signature dictionary and sign interface
options = new SignatureOptions();
options.setVisualSignature(signatureProperties);
// options.setPage(signatureProperties.getPage());
//options.setPreferedSignatureSize(signatureProperties.getPreferredSize());
doc.addSignature(signature, this, options);
doc.saveIncremental(fis, fos);
return outputDocument;
}
PDDocument openPDFDoc(File pdfFile) throws Exception
{
File originalPDF = pdfFile;
PDFParser parser = new PDFParser(new BufferedInputStream(new FileInputStream(originalPDF)));
parser.parse();
PDDocument originialPdfDoc = parser.getPDDocument();
boolean isOriginalDocEncrypted = originialPdfDoc.isEncrypted();
if (isOriginalDocEncrypted)
{
originialPdfDoc.openProtection(new StandardDecryptionMaterial("123456"));
}
return originialPdfDoc;
}
/**
* SignatureInterface implementation.
*
* This method will be called from inside of the pdfbox and create the pkcs7 signature.
* The given InputStream contains the bytes that are given by the byte range.
*
* This method is for internal use only. <-- TODO this method should be private
*
* Use your favorite cryptographic library to implement pkcs7 signature creation.
*/
#SuppressWarnings("deprecation")
#Override
public byte[] sign(InputStream content) throws IOException
{
CMSProcessableInputStream input = new CMSProcessableInputStream(content);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
// CertificateChain
List<Certificate> certList = Arrays.asList(cert);
CertStore certStore = null;
try
{
certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), provider);
gen.addSigner(privKey, (X509Certificate) certList.get(0), CMSSignedGenerator.DIGEST_SHA256);
gen.addCertificatesAndCRLs(certStore);
CMSSignedData signedData = gen.generate(input, false, provider);
return signedData.getEncoded();
}
catch (Exception e)
{
// should be handled
System.err.println("Error while creating pkcs7 signature.");
e.printStackTrace();
}
throw new RuntimeException("Problem while preparing signature");
}
public static void main(String[] args) throws Exception
{
//String pdfPath="E:\\outputs1\\iText in Action.pdf";
String pdfPath="E:\\outputs1\\CNB_20131029_AAPL034_0490301_NSEFO_ECN_iPass.pdf";
// new PdfOptimize().reducePdfSize(pdfPath);
File ksFile = new File("E:/sol.p12");
KeyStore keystore = KeyStore.getInstance("PKCS12", provider);
char[] pin = "xxxxxxx".toCharArray();
keystore.load(new FileInputStream(ksFile), pin);
//String pdfPath="E:\\temp\\pdf\\security\\password\\hello_iText.pdf";
File document = new File(pdfPath);
CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone());
FileInputStream image = new FileInputStream(RESOURCE);
PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(pdfPath, image, 1);
visibleSig.xAxis(660).yAxis(480).zoom(-50).signatureFieldName("signature");
visibleSig.height(37);
visibleSig.width(70);
//visibleSig.imageSizeInPercents(50);
PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
signatureProperties.signerName("XXXXXXX").signerLocation("chennai").signatureReason("Security").preferredSize(0)
.page(1).visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();
signatureProperties.setPdVisibleSignature(visibleSig);
signing.signPDF(document, signatureProperties);
}
}
And most of the methods are deprecated which are used to verify the owner password ,user password and etc.
Even the password you used is a correct one , when the PDF is Password protected it has some securities added to it. So you need to remove those securites.
In your openPDFDoc(File pdfFile) method
Add these lines to your method
if (isOriginalDocEncrypted)
{
originialPdfDoc.openProtection(new StandardDecryptionMaterial("123456"));
**originialPdfDoc.setAllSecurityToBeRemoved(true);**
}
This will remove the securities set to the PDF
Now you can do the job.
I am surfing the web-users pdf files from Domino Server. I have a template.pdf and a font file on my Java package to generate these pdf files without SAVING them on the server. However the PdfStamper requires me to use OutputStream which needs a path.
Does Domino Server have a temp space? Is there a different way to implement this? Is there a fake path to set?
As a test for now I'm saving it on my local machine.
package de.vogella.itext.write;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
public class FillUpPDF {
// Get the files from jar/package
InputStream streamTemplate = getClass().getResourceAsStream("Template1.pdf");
InputStream streamFont = getClass().getResourceAsStream("Ruritania.ttf");
// Files
public static final String sTemplate = "Template1.pdf";
public static final String sResultPDF = "C:/Test/Bob Info.pdf";
public static final String sResultFont = "Ruritania.ttf";
// Manipulates a PDF file source with the file destination as result
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
// Read the Template
PdfReader reader = new PdfReader(src);
// Copy the template and output it to the destination
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); //Where to fileoutputstream on Domino Server temporarily
// Gets the fields on the form
AcroFields form = stamper.getAcroFields();
// Create and set the font
BaseFont newFont = BaseFont.createFont(sResultFont, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
form.addSubstitutionFont(newFont);
/* Filling up the fields on the form */
form.setFieldProperty("text_1", "textfont", newFont, null);
form.setFieldProperty("text_1", "textsize", new Float(9), null);
form.setField("text_1", "Bob");
form.setFieldProperty("text_2", "textfont", newFont, null);
form.setFieldProperty("text_2", "textsize", new Float(9), null);
form.setField("text_2", "Gates");
form.setFieldProperty("text_3", "textfont", newFont, null);
form.setFieldProperty("text_3", "textsize", new Float(9), null);
form.setField("text_3", "Oct 17, 2013 at 11:00am");
form.setFieldProperty("text_4", "textfont", newFont, null);
form.setFieldProperty("text_4", "textsize", new Float(9), null);
form.setField("text_4", "Cloud and Smarter Infrastructure");
// Fixed the field
stamper.setFormFlattening(true);
stamper.setFreeTextFlattening(true);
// Close
stamper.close();
reader.close();
// Next Step: Send out the created pdf file to the user.
}
// Main method
public void main(String[] args) throws Exception {
FillUpPDF certification = new FillUpPDF();
//certification.manipulatePdf(sTemplate, sResultPDF);
certification.manipulatePdf(sTemplate, sResultPDF);
}
}
You do not need a temp file path. You can use the outputstream from the response and thereby send the PDF directly to the browser.
Example:
XspHttpServletResponse response = (XspHttpServletResponse) JSFUtil.getFacesContext().getExternalContext().getResponse();
ServletOutputStream out = response.getOutputStream();
PdfStamper stamper = new PdfStamper(reader, out);