How to show timestamp status in PDF signature appearance using itext - pdf

The adobe reader shows pdf signature status, valid and invalid.
I would like the reader to shows the dynamic(not static)timestamp status which is included in the signature.
The itext code I use is as follows.
PdfReader reader = new PdfReader(IN_FILE);
FileOutputStream fout = new FileOutputStream(OUT_FILE);
PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
PdfSignatureAppearance sap = stp.getSignatureAppearance();
sap.setCrypto(null, chain, null, PdfSignatureAppearance.SELF_SIGNED);
sap.setVisibleSignature(new Rectangle(100, 100, 300, 200), 1, "Signature");
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, new PdfName("adbe.pkcs7.detached"));
dic.setReason(sap.getReason());
dic.setLocation(sap.getLocation());
dic.setContact(sap.getContact());
dic.setDate(new PdfDate(sap.getSignDate()));
sap.setCryptoDictionary(dic);
int contentEstimated = 15000;
HashMap exc = new HashMap();
exc.put(PdfName.CONTENTS, new Integer(contentEstimated * 2 + 2));
sap.preClose(exc);
PDFTemplate sigLayer = PdfSignatureAppearance.getLayer(n);
is responsible for signature appearance. But I am unable to include the dynamic timestamp status.

The to-be-signed timestamp hash value is computed over the signed pdf, when the document's signature appearance has been created.
Modify the pdf adding the ts information will invalidate the signature...

Related

Adding Text Field to Digitally signed PDf breaks applied signature

I am trying to add text field with value using PDFBOX-3.0.0 to digitally signed document which allows form filling but it makes applied signature invalid.
Code
try ( InputStream resource = getClass().getResourceAsStream("SignatureVlidationTest.pdf");
PDDocument document = Loader.loadPDF(resource);
) {
PDPage page = document.getPage(0);
page.getCOSObject().setNeedToBeUpdated(true);
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
acroForm.getCOSObject().setNeedToBeUpdated(true);
PDTextField textBox = new PDTextField(acroForm);
textBox.setPartialName("SampleField");
textBox.setMultiline(true);
textBox.setDefaultAppearance("/Helv 14 Tf 1 0 0 rg");
textBox.setReadOnly(true);
textBox.setValue("label");
float pw = page.getMediaBox().getUpperRightX();
float ph = page.getMediaBox().getUpperRightY();
// Specify the widget annotation associated with the field
PDAnnotationWidget widget = textBox.getWidgets().get(0);
PDRectangle rect = new PDRectangle(pw - 110, ph - 25, 110, 25);
widget.setRectangle(rect);
widget.getCOSObject().setNeedToBeUpdated(true);
widget.setPage(page);
widget.setPrinted(true);
widget.setReadOnly(true);
page.getAnnotations().add(widget);
page.getCOSObject().setNeedToBeUpdated(true);
acroForm.getFields().add(textBox);
document.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
Set<COSDictionary> objectsToWrite = new HashSet<>();
objectsToWrite.add(page.getCOSObject());
document.saveIncremental(new FileOutputStream(new File(RESULT_FOLDER, "SignatureVlidationTest-ImageAnnotationAdded.pdf")),objectsToWrite );
}

PDFs generated with iTextSharp generated watermark giving error

We are applying a watermark using iTextSharp to PDF documents before passing them to client. On some machines (all using v.11 of PDF viewer), the following error is being displayed.
An error exists on this page. Acrobat may not display the page correctly. Please contact the person who created the PDF Document to correct the problem.
The watermarking code is as follows:
protected static byte[] GetStampedDocument(byte[] content, string mark, string heading)
{
PdfReader reader = new PdfReader(content);
using (MemoryStream stream = new MemoryStream())
{
PdfStamper pdfStamper = new PdfStamper(reader, stream);
for (int i = 1; i <= reader.NumberOfPages; i++)
{
iTextSharp.text.Rectangle pageSize = reader.GetPageSizeWithRotation(i);
PdfContentByte pdfPageContents = pdfStamper.GetOverContent(i);
pdfPageContents.BeginText();
PdfGState gstate = new PdfGState();
gstate.FillOpacity = 0.2f;
gstate.StrokeOpacity = 0.3f;
pdfPageContents.SaveState();
pdfPageContents.SetGState(gstate);
BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false);
pdfPageContents.SetFontAndSize(baseFont, 46);
pdfPageContents.SetRGBColorFill(32, 32, 32);
pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, mark, pageSize.Width / 2, pageSize.Height / 2, 66);
if (heading != null && heading.Length > 0)
{
pdfPageContents.SetFontAndSize(baseFont, 12);
pdfPageContents.SetRGBColorFill(32, 32, 32);
pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_LEFT, heading, 5, pageSize.Height - 15, 0);
}
pdfPageContents.EndText();
pdfPageContents.RestoreState();
}
pdfStamper.FormFlattening = true;
pdfStamper.FreeTextFlattening = true;
pdfStamper.Close();
return stream.ToArray();
}
}
I cannot recreate this on any machine I have tried so there is an environmental element to this as well I expect.
Any ideas?
You save the graphics state inside a text object:
pdfPageContents.BeginText();
[...]
pdfPageContents.SaveState();
[...]
pdfPageContents.EndText();
pdfPageContents.RestoreState();
This is not allowed, cf. Figure 9 — Graphics objects — in ISO 32000-2, special graphics state operators (like saving or restoring the graphics state) may not be used inside a text object.
To prevent this invalid syntax, move pdfPageContents.SaveState() before pdfPageContents.BeginText(). This furthermore makes the nesting of saving/restoring the state and beginning and ending the text object more natural.

How to convert a PDF generating in response.outputStream to a Base64 encoding

I am doing a project where i need to create a admit card for student who are appearing in examination. The pdf Generation part is working fine but my problem is i have to encode my pdf to Base64 format. I am not finding any solution. My code are given as bellow
public void downloadPdf() throws IOException, DocumentException {
System.out.println("hi i ma in");
resultList=examinationDetailsService.readAdmitCardData();
for(Object[] data:resultList)
{
personalDetails=(PersonalDetails)data[0];
System.out.println("name"+personalDetails.getApplicantName());
rollNoAssign=(RollNoAssign)data[1];
System.out.println("rollno"+rollNoAssign.getRollNo());
examDateAssign=(ExamDateAssign)data[2];
}
//Converting Date
SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy");
String date = DATE_FORMAT.format(examDateAssign.getExaminationDate());
// Get the FacesContext
FacesContext facesContext = FacesContext.getCurrentInstance();
// Get HTTP response
HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
// Set response headers
response.reset(); // Reset the response in the first place
response.setHeader("Content-Type", "application/pdf"); // Set only the content type
// Open response output stream
OutputStream responseOutputStream = response.getOutputStream();
Document document = new Document(PageSize.A4, 0, 0, 0, 0);
PdfWriter.getInstance(document,response.getOutputStream());
document.open();
PdfPTable maintable = new PdfPTable(1);
maintable.setWidthPercentage(90);
maintable.setSpacingBefore(0f);
maintable.setSpacingAfter(0f);
Paragraph ph1 = new Paragraph();
ph1.add(new Chunk("\n\nGOVERNMENT OF ASSAM \nOFFICE OF THE ELECTRICAL LICENSING BOARD, ASSAM\n1", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12, Font.NORMAL)));
//ph1.add(new Chunk("ST", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12, Font.NORMAL)));
Chunk superScript = new Chunk("ST", FontFactory.getFont(FontFactory.TIMES_ROMAN, 8, Font.NORMAL));
superScript.setTextRise(5f);
ph1.add(superScript);
ph1.add(new Chunk(" FLOOR, WEST END BLOCK, HOUSEFED COMPLEX,DISPUR, GUWAHATI-781006, ASSAM.", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12, Font.NORMAL)));
ph1.add(new Chunk("\n***\n", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12, Font.BOLD)));
ph1.add(new Chunk("\nADMIT CARD", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12, Font.BOLD)));
PdfPCell heading1 = new PdfPCell(ph1);
heading1.setBorder(0);
heading1.setHorizontalAlignment(Element.ALIGN_CENTER);
heading1.setVerticalAlignment(Element.ALIGN_CENTER);
maintable.addCell(heading1);
PdfPTable maintable1 = new PdfPTable(1);
maintable1.setWidthPercentage(87);
maintable1.setSpacingBefore(0f);
maintable1.setSpacingAfter(0f);
Paragraph ph2 = new Paragraph();
ph2.add(new Chunk("\n\nShri/Smti "+personalDetails.getApplicantName()+", Roll No. "+rollNoAssign.getRollNo()+" is hereby "
+ "allowed to appear in the examination for grant of Electrical Supervisor's Certificate of Competency "
+ "to be held at "+ rollNoAssign.getVenue().getName()
+ "as per schedule given below:", FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.NORMAL)));
ph2.add(new Chunk("\n\n Viva-voce", FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.BOLD)));
ph2.add(new Chunk(" test on "+date+ " at 9 AM/12.30 PM ;", FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.NORMAL)));
ph2.add(new Chunk(" Written", FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.BOLD)));
ph2.add(new Chunk(" test on __________ at 9 AM.", FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.NORMAL)));
ph2.add(new Chunk("\n\n\nPlease bring the followings with you while coming for the said examinations: \n"
+ "\n1.Original copy of Degree/Diploma/ITI Certificate/Supervisor's Certificate of Competency/"
+ "Workmen's Permit\n\n belonging to you and this Admit Card in original.\n"
+ "\n2.Detail experience certificate(s) relevant to the part(s) of Supervisor's examination applied for.\n"
+ "\n3.\n"
+ "\n\nNB: (a) No alteration is allowed in the entries on this Admit Card without the authority of the Board."
+ "\n (b) No expense(s) incurred by any candidate will be borne by the Board.\n\n\n", FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.NORMAL)));
PdfPCell heading2 = new PdfPCell(ph2);
heading2.setBorder(0);
heading2.setHorizontalAlignment(Element.ALIGN_JUSTIFIED);
heading2.setVerticalAlignment(Element.ALIGN_CENTER);
maintable1.addCell(heading2);
PdfPTable maintable2 = new PdfPTable(2);
float[] columnWidths = new float[]{55f, 45f};
maintable2.setWidths(columnWidths);
maintable2.setWidthPercentage(84);
maintable2.setSpacingBefore(0f);
maintable2.setSpacingAfter(0f);
Paragraph ph31 = new Paragraph();
ph31.add(new Chunk("Details furnished by you in the application form and/or examination process are used by the Board"
+ " for further needful, hence, if you feel any correction(s) in the same is/are required, please get those done before"
+ " leaving the examination venue. The Board shall not be under any obligation of removing the difficulties arising later"
+ " on out of incorrect/improper information furnished by you or non-furnishing of required ones.\n", FontFactory.getFont(FontFactory.COURIER, 10, Font.NORMAL)));
PdfPCell heading31 = new PdfPCell(ph31);
heading31.setBorder(15);
heading31.setHorizontalAlignment(Element.ALIGN_JUSTIFIED);
heading31.setVerticalAlignment(Element.ALIGN_LEFT);
maintable2.addCell(heading31);
Paragraph ph32 = new Paragraph();
ph32.add(new Chunk("\n\n\n(Member Secretary)\nElectrical Licensing Board,\nAssam.", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12, Font.NORMAL)));
PdfPCell heading32 = new PdfPCell(ph32);
heading32.setBorder(0);
heading32.setHorizontalAlignment(Element.ALIGN_CENTER);
heading32.setVerticalAlignment(Element.ALIGN_CENTER);
maintable2.addCell(heading32);
document.add(maintable);
document.add(maintable1);
document.add(maintable2);
document.close();
/* // Read PDF contents
URL url = new URL(PDF_URL);
InputStream pdfInputStream = url.openStream();*/
// Read PDF contents and write them to the output
byte[] bytesBuffer = new byte[2048];
int bytesRead;
/* while ((bytesRead = pdfInputStream.read(bytesBuffer)) > 0) {
responseOutputStream.write(bytesBuffer, 0, bytesRead);
}
*/
Base64 encoder = new Base64();
byte[] decodedBytes = encoder.o
// Make sure that everything is out
responseOutputStream.write(decodedBytes);
responseOutputStream.flush();
// Close both streams
//pdfInputStream.close();
responseOutputStream.close();
// JSF doc:
// Signal the JavaServer Faces implementation that the HTTP response for this request has already been generated
// (such as an HTTP redirect), and that the request processing lifecycle should be terminated
// as soon as the current phase is completed.
facesContext.responseComplete();
}
Please give me any solution. i using itext
When I look at your code, I see:
PdfWriter.getInstance(document,response.getOutputStream());
Which means that you are instructing iText to write PDF bytes straight to the browser. This outputstream is closed at the moment you close the document.
I also see:
OutputStream responseOutputStream = response.getOutputStream();
I even see that you try adding stuff to this stream. This is impossible as the stream is already closed.
You need to create a ByteArrayOutputStream like this:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
And use this in the PdfWriter:
PdfWriter.getInstance(document, baos);
Now you can get the PDF bytes like this:
byte[] pdf = baos.toByteArray();
Now you can encode these bytes and send them to the output stream.
Encode:
Assuming that you are using org.apache.commons.codec.binary.Base64 as explained in the answer to Base64 Encoding in Java, you can do this:
byte[] base64 = Base64.encodeBase64(pdf);
(There are other ways to do this.)
Send to output stream:
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentType("application/pdf");
response.setContentLength(base64.length);
OutputStream os = response.getOutputStream();
os.write(base64);
os.flush();
os.close();

Changing Date Format on PDF Signature Stamp

I can sign a pdf file, but the time format is too long.
I wabt to change Date format, but I couldnt..
Here is my code.
PdfReader reader = new PdfReader(input);
PdfStamper stp = PdfStamper.CreateSignature(reader, output, '\0');
PdfSignatureAppearance sap = stp.SignatureAppearance;
**sap.SignDate = DateTime.Now;**
sap.SetCrypto(null, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
sap.Reason = "Testování";
sap.Location = "Praha";
sap.Acro6Layers = true;
sap.Render = PdfSignatureAppearance.SignatureRender.GraphicAndDescription;
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
**dic.Date = new PdfDate(sap.SignDate);**
And, at the my pdf file, the signature stamp is like this:
"2012.11.01 05:21:00 +02:00"
but I want to like that: "01.11.2012 19:21:00"
Please go to http://itextpdf.com/book/digitalsignatures and read section 2.4 to find out how to create different signature appearances.

Customize PDFStamper using iTextSharp

I'm using iTextSharp to sign PDFs. When signing, it stamps the document with 4 fields: who signed, when, reason and location. What I meant to do is to add a field below (or above, that doesn't matter) with custom information.
Any Idea?
Here's my code that is generating the stamp:
PdfStamper stp = PdfStamper.CreateSignature(reader, memoryOut, '\0');
PdfSignatureAppearance sap = stp.SignatureAppearance;
iTextSharp.text.Rectangle rectangle = new iTextSharp.text.Rectangle(100, 100, 500, 200);
sap.SetVisibleSignature(rectangle, stp.Reader.NumberOfPages, null);
sap.SignDate = DateTime.Now;
sap.SetCrypto(null, chain, null, null);
sap.Reason = ssReason;
sap.Contact = ssContact;
sap.Location = ssLocation;
sap.Acro6Layers = true;
//sap.SignatureGraphic = iTextSharp.text.Image.GetInstance(ssImageUrl);
//sap.SignatureGraphic.ScaleToFit(131, 45);
sap.Render = PdfSignatureAppearance.SignatureRender.Description;
Several options:
modify one of the PdfTemplates from sap.getLayer(int).
call sap.setLayer2Text() to include your extra information.
Use a graphic. You can wrap a PdfTemplate in an Image, so you can draw anything you want. Then
sap.Render = PdfSignatureAppearance.SignatureRender.GraphicAndDescription
Hack The Source.