Digital signatures - chapter 2
These examples were written in the context of Chapter 2 - "PDF and digital signatures" of the Digital Signatures for PDF documents eBook.
c2_01_signhelloworld
A simple example of adding a visible signature to a document:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C2_01_SignHelloWorld {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"hello_signed1.pdf",
"hello_signed2.pdf",
"hello_signed3.pdf",
"hello_signed4.pdf"
};
public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard signatureType, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
Rectangle rect = new Rectangle(36, 648, 200, 100);
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance
.setReason(reason)
.setLocation(location)
// Specify if the appearance before field is signed will be used
// as a background for the signed field. The "false" value is the default value.
.setReuseAppearance(false)
.setPageRect(rect)
.setPageNumber(1);
signer.setFieldName("sig");
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, signatureType);
}
public static void main(String[] args) throws GeneralSecurityException, IOException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
C2_01_SignHelloWorld app = new C2_01_SignHelloWorld();
app.sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
app.sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA512, provider.getName(),
PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
app.sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
app.sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.RIPEMD160, provider.getName(),
PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_01_SignHelloWorld
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"hello_signed1.pdf",
"hello_signed2.pdf",
"hello_signed3.pdf",
"hello_signed4.pdf"
};
public void Sign(String src, String dest, X509Certificate[] chain, ICipherParameters pk,
String digestAlgorithm, PdfSigner.CryptoStandard subfilter, String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
Rectangle rect = new Rectangle(36, 648, 200, 100);
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance
.SetReason(reason)
.SetLocation(location)
// Specify if the appearance before field is signed will be used
// as a background for the signed field. The "false" value is the default value.
.SetReuseAppearance(false)
.SetPageRect(rect)
.SetPageNumber(1);
signer.SetFieldName("sig");
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
C2_01_SignHelloWorld app = new C2_01_SignHelloWorld();
app.Sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
app.Sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA512,
PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
app.Sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
app.Sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.RIPEMD160,
PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
}
}
}
c2_02_signhelloworldwithtempfile
Signing a document using a temporary file to avoid OutOfMemoryExceptions
with large PDFs:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
public class C2_02_SignHelloWorldWithTempFile {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"hello_signed_with_temp.pdf"
};
public void sign(String src, String temp, String dest, Certificate[] chain, PrivateKey pk,
String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
// Pass the temporary file's path to the PdfSigner constructor
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), temp, new StampingProperties());
// Create the signature appearance
Rectangle rect = new Rectangle(36, 648, 200, 100);
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance
.setReason(reason)
.setLocation(location)
// Specify if the appearance before field is signed will be used
// as a background for the signed field. The "false" value is the default value.
.setReuseAppearance(false)
.setPageRect(rect)
.setPageNumber(1);
signer.setFieldName("sig");
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws GeneralSecurityException, IOException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
new C2_02_SignHelloWorldWithTempFile().sign(SRC, DEST, DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Temp test", "Ghent");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_02_SignHelloWorldWithTempFile
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"hello_signed_with_temp.pdf"
};
public void Sign(String src, String tmp, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
// Pass the temporary file's path to the PdfSigner constructor
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), tmp,
new StampingProperties());
// Create the signature appearance
Rectangle rect = new Rectangle(36, 648, 200, 100);
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance
.SetReason(reason)
.SetLocation(location)
// Specify if the appearance before field is signed will be used
// as a background for the signed field. The "false" value is the default value.
.SetReuseAppearance(false)
.SetPageRect(rect)
.SetPageNumber(1);
signer.SetFieldName("sig");
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
new C2_02_SignHelloWorldWithTempFile().Sign(SRC, DEST, DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CMS, "Temp test", "Ghent");
}
}
}
c2_03_signemptyfield
Signing an empty text field with iText:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C2_03_SignEmptyField {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"field_signed1.pdf",
"field_signed2.pdf",
"field_signed3.pdf",
"field_signed4.pdf"
};
public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
// Specify if the appearance before field is signed will be used
// as a background for the signed field. The "false" value is the default value.
.setReuseAppearance(false);
// This name corresponds to the name of the field that already exists in the document.
signer.setFieldName(name);
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws GeneralSecurityException, IOException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
C2_03_SignEmptyField app = new C2_03_SignEmptyField();
app.sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
app.sign(SRC, "Signature1", DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA512,
provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
app.sign(SRC, "Signature1", DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256,
provider.getName(), PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
app.sign(SRC, "Signature1", DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.RIPEMD160,
provider.getName(), PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_03_SignEmptyField
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"field_signed1.pdf",
"field_signed2.pdf",
"field_signed3.pdf",
"field_signed4.pdf"
};
public void Sign(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
signer.GetSignatureAppearance()
.SetReason(reason)
.SetLocation(location)
// Specify if the appearance before field is signed will be used
// as a background for the signed field. The "false" value is the default value.
.SetReuseAppearance(false);
// This name corresponds to the name of the field that already exists in the document.
signer.SetFieldName(name);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
C2_03_SignEmptyField app = new C2_03_SignEmptyField();
app.Sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Test 1", "Ghent");
app.Sign(SRC, "Signature1", DEST + RESULT_FILES[1], chain, pk,
DigestAlgorithms.SHA512, PdfSigner.CryptoStandard.CMS,
"Test 2", "Ghent");
app.Sign(SRC, "Signature1", DEST + RESULT_FILES[2], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CADES,
"Test 3", "Ghent");
app.Sign(SRC, "Signature1", DEST + RESULT_FILES[3], chain, pk,
DigestAlgorithms.RIPEMD160, PdfSigner.CryptoStandard.CADES,
"Test 4", "Ghent");
}
}
}
c2_04_createemptyfield
Creating an empty text field with iText:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.PdfSignatureFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
public class C2_04_CreateEmptyField {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String SIGNAME = "Signature1";
public static final String[] RESULT_FILES = new String[]{
"hello_empty.pdf",
"hello_empty2.pdf",
"field_signed.pdf"
};
public void createPdf(String filename) throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(filename));
Document doc = new Document(pdfDoc);
doc.add(new Paragraph("Hello World!"));
// Create a signature form field
PdfFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
.setWidgetRectangle(new Rectangle(72, 632, 200, 100)).createSignature();
field.getFirstFormAnnotation().setPage(1);
// Set the widget properties
field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT).setFlags(PdfAnnotation.PRINT);
PdfDictionary mkDictionary = field.getWidgets().get(0).getAppearanceCharacteristics();
if (null == mkDictionary) {
mkDictionary = new PdfDictionary();
}
PdfArray black = new PdfArray();
black.add(new PdfNumber(ColorConstants.BLACK.getColorValue()[0]));
black.add(new PdfNumber(ColorConstants.BLACK.getColorValue()[1]));
black.add(new PdfNumber(ColorConstants.BLACK.getColorValue()[2]));
mkDictionary.put(PdfName.BC, black);
field.getWidgets().get(0).setAppearanceCharacteristics(mkDictionary);
PdfAcroForm.getAcroForm(pdfDoc, true).addField(field);
Rectangle rect = new Rectangle(0, 0, 200, 100);
PdfFormXObject xObject = new PdfFormXObject(rect);
PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);
canvas
.setStrokeColor(ColorConstants.BLUE)
.setFillColor(ColorConstants.LIGHT_GRAY)
.rectangle(0 + 0.5, 0 + 0.5, 200 - 0.5, 100 - 0.5)
.fillStroke()
.setFillColor(ColorConstants.BLUE);
new Canvas(canvas, rect).showTextAligned("SIGN HERE", 100, 50,
TextAlignment.CENTER, (float) Math.toRadians(25));
// Note that Acrobat doesn't show normal appearance in the highlight mode.
field.getWidgets().get(0).setNormalAppearance(xObject.getPdfObject());
doc.close();
}
public void addField(String src, String dest) throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
// Create a signature form field
PdfSignatureFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
.setWidgetRectangle(new Rectangle(72, 632, 200, 100)).createSignature();
field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_OUTLINE).setFlags(PdfAnnotation.PRINT);
PdfAcroForm.getAcroForm(pdfDoc, true).addField(field);
pdfDoc.close();
}
public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location);
signer.setFieldName(name);
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
C2_04_CreateEmptyField app = new C2_04_CreateEmptyField();
app.createPdf(DEST + RESULT_FILES[0]);
app.addField(SRC, DEST + RESULT_FILES[1]);
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
app.sign(DEST + RESULT_FILES[0], SIGNAME, DEST + RESULT_FILES[2], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Test", "Ghent");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Colors;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_04_CreateEmptyField
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public const String SIGNAME = "Signature1";
public static readonly String[] RESULT_FILES =
{
"hello_empty.pdf",
"hello_empty2.pdf",
"field_signed.pdf"
};
public void CreatePdf(String filename)
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(filename));
Document doc = new Document(pdfDoc);
doc.Add(new Paragraph("Hello World!"));
// Create a signature form field
PdfFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
.SetWidgetRectangle(new Rectangle(72, 632, 200, 100)).CreateSignature();
field.GetFirstFormAnnotation().SetPage(1);
// Set the widget properties
field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT).SetFlags(PdfAnnotation.PRINT);
PdfDictionary mkDictionary = field.GetWidgets()[0].GetAppearanceCharacteristics();
if (null == mkDictionary)
{
mkDictionary = new PdfDictionary();
}
PdfArray black = new PdfArray();
black.Add(new PdfNumber(ColorConstants.BLACK.GetColorValue()[0]));
black.Add(new PdfNumber(ColorConstants.BLACK.GetColorValue()[1]));
black.Add(new PdfNumber(ColorConstants.BLACK.GetColorValue()[2]));
mkDictionary.Put(PdfName.BC, black);
field.GetWidgets()[0].SetAppearanceCharacteristics(mkDictionary);
PdfFormCreator.GetAcroForm(pdfDoc, true).AddField(field);
Rectangle rect = new Rectangle(0, 0, 200, 100);
PdfFormXObject xObject = new PdfFormXObject(rect);
PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);
canvas
.SetStrokeColor(ColorConstants.BLUE)
.SetFillColor(ColorConstants.LIGHT_GRAY)
.Rectangle(0 + 0.5, 0 + 0.5, 200 - 0.5, 100 - 0.5)
.FillStroke()
.SetFillColor(ColorConstants.BLUE);
new Canvas(canvas, rect).ShowTextAligned("SIGN HERE", 100, 50,
TextAlignment.CENTER, (float) (Math.PI / 180) * 25);
// Note that Acrobat doesn't show normal appearance in the highlight mode.
field.GetWidgets()[0].SetNormalAppearance(xObject.GetPdfObject());
doc.Close();
}
public void AddField(String src, String dest)
{
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
// Create a signature form field
PdfSignatureFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
.SetWidgetRectangle(new Rectangle(72, 632, 200, 100)).CreateSignature();
field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_OUTLINE).SetFlags(PdfAnnotation.PRINT);
PdfFormCreator.GetAcroForm(pdfDoc, true).AddField(field);
pdfDoc.Close();
}
public void Sign(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
signer.GetSignatureAppearance()
.SetReason(reason)
.SetLocation(location);
signer.SetFieldName(name);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
C2_04_CreateEmptyField appCreate = new C2_04_CreateEmptyField();
appCreate.CreatePdf(DEST + RESULT_FILES[0]);
appCreate.AddField(SRC, DEST + RESULT_FILES[1]);
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
new C2_04_CreateEmptyField().Sign(DEST + RESULT_FILES[0], SIGNAME, DEST + RESULT_FILES[2],
chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Test", "Ghent");
}
}
}
c2_05_customappearance
Creating a custom appearance for the signature by adding a grey background:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C2_05_CustomAppearance {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"signature_custom.pdf"
};
public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider,
PdfSigner.CryptoStandard subfilter,
String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location);
// This name corresponds to the name of the field that already exists in the document.
signer.setFieldName(name);
// Get the background layer and draw a gray rectangle as a background.
PdfFormXObject n0 = appearance.getLayer0();
float x = n0.getBBox().toRectangle().getLeft();
float y = n0.getBBox().toRectangle().getBottom();
float width = n0.getBBox().toRectangle().getWidth();
float height = n0.getBBox().toRectangle().getHeight();
PdfCanvas canvas = new PdfCanvas(n0, signer.getDocument());
canvas.setFillColor(ColorConstants.LIGHT_GRAY);
canvas.rectangle(x, y, width, height);
canvas.fill();
// Set the signature information on layer 2
PdfFormXObject n2 = appearance.getLayer2();
Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
new Canvas(n2, signer.getDocument()).add(p);
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
new C2_05_CustomAppearance().sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Custom appearance example", "Ghent");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using iText.Kernel.Colors;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_05_CustomAppearance
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"signature_custom.pdf"
};
public void Sign(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance
.SetReason(reason)
.SetLocation(location);
// This name corresponds to the name of the field that already exists in the document.
signer.SetFieldName(name);
// Get the background layer and draw a gray rectangle as a background.
PdfFormXObject n0 = appearance.GetLayer0();
float x = n0.GetBBox().ToRectangle().GetLeft();
float y = n0.GetBBox().ToRectangle().GetBottom();
float width = n0.GetBBox().ToRectangle().GetWidth();
float height = n0.GetBBox().ToRectangle().GetHeight();
PdfCanvas canvas = new PdfCanvas(n0, signer.GetDocument());
canvas.SetFillColor(ColorConstants.LIGHT_GRAY);
canvas.Rectangle(x, y, width, height);
canvas.Fill();
// Set the signature information on layer 2
PdfFormXObject n2 = appearance.GetLayer2();
Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
new Canvas(n2, signer.GetDocument()).Add(p);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
new C2_05_CustomAppearance().Sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Custom appearance example", "Ghent");
}
}
}
c2_06_signatureappearance
Creating custom text, custom fonts and using right-to-left writing in a signature:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.font.PdfFontFactory.EmbeddingStrategy;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.properties.BaseDirection;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
public class C2_06_SignatureAppearance {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
public static final String IMG = "./src/test/resources/img/1t3xt.gif";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"signature_appearance1.pdf",
"signature_appearance2.pdf",
"signature_appearance3.pdf",
"signature_appearance4.pdf"
};
public void sign1(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
// This name corresponds to the name of the field that already exists in the document.
signer.setFieldName(name);
// Set the custom text and a custom font
appearance.setLayer2Text("This document was signed by Bruno Specimen");
appearance.setLayer2Font(PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN));
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public void sign2(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
signer.setFieldName(name);
// Creating the appearance for layer 2
PdfFormXObject n2 = appearance.getLayer2();
// Set custom text, custom font, and right-to-left writing.
// Characters: لورانس العرب
Text text = new Text("\u0644\u0648\u0631\u0627\u0646\u0633 \u0627\u0644\u0639\u0631\u0628");
text.setFont(PdfFontFactory.createFont("./src/test/resources/font/NotoNaskhArabic-Regular.ttf",
PdfEncodings.IDENTITY_H, EmbeddingStrategy.PREFER_EMBEDDED));
text.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);
new Canvas(n2, signer.getDocument()).add(new Paragraph(text).setTextAlignment(TextAlignment.RIGHT));
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public void sign3(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
signer.setFieldName(name);
// Set a custom text and a background image
appearance.setLayer2Text("This document was signed by Bruno Specimen");
appearance.setImage(ImageDataFactory.create(IMG));
appearance.setImageScale(1);
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public void sign4(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
signer.setFieldName(name);
// Set a custom text and a scaled background image
appearance.setLayer2Text("This document was signed by Bruno Specimen");
appearance.setImage(ImageDataFactory.create(IMG));
appearance.setImageScale(-1);
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
C2_06_SignatureAppearance app = new C2_06_SignatureAppearance();
String signatureName = "Signature1";
String signatureReason = "Custom appearance example";
String location = "Ghent";
app.sign1(SRC, signatureName, DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
signatureReason, location);
app.sign2(SRC, signatureName, DEST + RESULT_FILES[1], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
signatureReason, location);
app.sign3(SRC, signatureName, DEST + RESULT_FILES[2], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
signatureReason, location);
app.sign4(SRC, signatureName, DEST + RESULT_FILES[3], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
signatureReason, location);
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using iText.IO.Font;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.IO.Font.Constants;
using iText.IO.Image;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_06_SignatureAppearance
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string IMG = "../../../resources/img/1t3xt.gif";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"signature_appearance1.pdf",
"signature_appearance2.pdf",
"signature_appearance3.pdf",
"signature_appearance4.pdf"
};
public void Sign1(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance
.SetReason(reason)
.SetLocation(location);
// This name corresponds to the name of the field that already exists in the document.
signer.SetFieldName(name);
// Set the custom text and a custom font
appearance.SetLayer2Text("This document was signed by Bruno Specimen");
appearance.SetLayer2Font(PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN));
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public void Sign2(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
signer.SetFieldName(name);
// Creating the appearance for layer 2
PdfFormXObject n2 = appearance.GetLayer2();
// Custom text, custom font, and right-to-left writing
// Characters: لورانس العرب
Text text = new Text("\u0644\u0648\u0631\u0627\u0646\u0633 \u0627\u0644\u0639\u0631\u0628");
text.SetFont(PdfFontFactory.CreateFont("../../../resources/font/NotoNaskhArabic-Regular.ttf",
PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED));
text.SetBaseDirection(BaseDirection.RIGHT_TO_LEFT);
new Canvas(n2, signer.GetDocument()).Add(new Paragraph(text).SetTextAlignment(TextAlignment.RIGHT));
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public void Sign3(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
signer.SetFieldName(name);
// Set a custom text and background image
appearance.SetLayer2Text("This document was signed by Bruno Specimen");
appearance.SetImage(ImageDataFactory.Create(IMG));
appearance.SetImageScale(1);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public void Sign4(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
signer.SetFieldName(name);
// Set a custom text and a scaled background image
appearance.SetLayer2Text("This document was signed by Bruno Specimen");
appearance.SetImage(ImageDataFactory.Create(IMG));
appearance.SetImageScale(-1);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
C2_06_SignatureAppearance app = new C2_06_SignatureAppearance();
app.Sign1(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Custom appearance example", "Ghent");
app.Sign2(SRC, "Signature1", DEST + RESULT_FILES[1], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Custom appearance example", "Ghent");
app.Sign3(SRC, "Signature1", DEST + RESULT_FILES[2], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Custom appearance example", "Ghent");
app.Sign4(SRC, "Signature1", DEST + RESULT_FILES[3], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Custom appearance example", "Ghent");
}
}
}
c2_07_signatureappearances
Adding a custom image:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
import java.util.Date;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C2_07_SignatureAppearances {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
public static final String IMG = "./src/test/resources/img/1t3xt.gif";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"signature_appearance_1.pdf",
"signature_appearance_2.pdf",
"signature_appearance_3.pdf",
"signature_appearance_4.pdf"
};
public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location,
PdfSignatureAppearance.RenderingMode renderingMode, ImageData image)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
// This name corresponds to the name of the field that already exists in the document.
signer.setFieldName(name);
appearance.setLayer2Text("Signed on " + new Date().toString());
// Set the rendering mode for this signature.
appearance.setRenderingMode(renderingMode);
// Set the Image object to render when the rendering mode is set to RenderingMode.GRAPHIC
// or RenderingMode.GRAPHIC_AND_DESCRIPTION.
appearance.setSignatureGraphic(image);
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
ImageData image = ImageDataFactory.create(IMG);
C2_07_SignatureAppearances app = new C2_07_SignatureAppearances();
String signatureName = "Signature1";
String location = "Ghent";
app.sign(SRC, signatureName, DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Appearance 1", location, PdfSignatureAppearance.RenderingMode.DESCRIPTION, null);
app.sign(SRC, signatureName, DEST + RESULT_FILES[1], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Appearance 2", location, PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION, null);
app.sign(SRC, signatureName, DEST + RESULT_FILES[2], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Appearance 3", location, PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION, image);
app.sign(SRC, signatureName, DEST + RESULT_FILES[3], chain, pk,
DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
"Appearance 4", location, PdfSignatureAppearance.RenderingMode.GRAPHIC, image);
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.IO.Image;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_07_SignatureAppearances
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
public static readonly string IMG = "../../../resources/img/1t3xt.gif";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"signature_appearance_1.pdf",
"signature_appearance_2.pdf",
"signature_appearance_3.pdf",
"signature_appearance_4.pdf"
};
public void Sign(String src, String name, String dest, X509Certificate[] chain,
ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
String reason, String location, PdfSignatureAppearance.RenderingMode renderingMode, ImageData image)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
// This name corresponds to the name of the field that already exists in the document.
signer.SetFieldName(name);
appearance.SetLayer2Text("Signed on " + DateTime.Now);
// Set the rendering mode for this signature.
appearance.SetRenderingMode(renderingMode);
// Set the Image object to render when the rendering mode is set to RenderingMode.GRAPHIC
// or RenderingMode.GRAPHIC_AND_DESCRIPTION.
appearance.SetSignatureGraphic(image);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
ImageData image = ImageDataFactory.Create(IMG);
C2_07_SignatureAppearances app = new C2_07_SignatureAppearances();
String signatureName = "Signature1";
String location = "Ghent";
app.Sign(SRC, signatureName, DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Appearance 1", location, PdfSignatureAppearance.RenderingMode.DESCRIPTION, null);
app.Sign(SRC, signatureName, DEST + RESULT_FILES[1], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Appearance 2", location, PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION, null);
app.Sign(SRC, signatureName, DEST + RESULT_FILES[2], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Appearance 3", location, PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION, image);
app.Sign(SRC, signatureName, DEST + RESULT_FILES[3], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Appearance 4", location, PdfSignatureAppearance.RenderingMode.GRAPHIC, image);
}
}
}
c2_08_signaturemetadata
Adding metadata to the signature dictionary:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C2_08_SignatureMetadata {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"field_metadata.pdf"
};
public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk,
String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
String reason, String location, String contact, final String fullName)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setContact(contact);
// This name corresponds to the name of the field that already exists in the document.
signer.setFieldName(name);
// Set the signature event to allow modification of the signature dictionary.
signer.setSignatureEvent(
new PdfSigner.ISignatureEvent() {
@Override
public void getSignatureDictionary(PdfSignature sig) {
sig.put(PdfName.Name, new PdfString(fullName));
}
}
);
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
C2_08_SignatureMetadata app = new C2_08_SignatureMetadata();
app.sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
provider.getName(), PdfSigner.CryptoStandard.CMS, "Test metadata",
"Ghent", "555 123 456", "Bruno L. Specimen");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_08_SignatureMetadata
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"field_metadata.pdf"
};
public void Sign(String src, String name, String dest, X509Certificate[] chain, ICipherParameters pk,
String digestAlgorithm, PdfSigner.CryptoStandard subfilter, String reason, String location,
String contact, String fullName)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
appearance.SetContact(contact);
signer.SetFieldName(name);
// Set the signature event to allow modification of the signature dictionary.
signer.SetSignatureEvent(new CustomISignatureEvent(fullName));
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
C2_08_SignatureMetadata app = new C2_08_SignatureMetadata();
app.Sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Test metadata", "Ghent", "555 123 456", "Bruno L. Specimen");
}
private class CustomISignatureEvent : PdfSigner.ISignatureEvent
{
private readonly String fullName;
public CustomISignatureEvent(String fullName)
{
this.fullName = fullName;
}
public void GetSignatureDictionary(PdfSignature sig)
{
sig.Put(PdfName.Name, new PdfString(fullName));
}
}
}
}
c2_09_signaturetypes
Ordinary (approval) and Certification (author) signatures:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextAnnotation;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C2_09_SignatureTypes {
public static final String DEST = "./target/signatures/chapter02/";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"hello_level_1.pdf", "hello_level_2.pdf",
"hello_level_3.pdf", "hello_level_4.pdf",
"hello_level_1_annotated.pdf", "hello_level_2_annotated.pdf",
"hello_level_3_annotated.pdf", "hello_level_4_annotated.pdf",
"hello_level_1_annotated_wrong.pdf", "hello_level_1_text.pdf",
"hello_level_1_double.pdf", "hello_level_2_double.pdf",
"hello_level_3_double.pdf", "hello_level_4_double.pdf",
};
public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, int certificationLevel,
String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
Rectangle rect = new Rectangle(36, 648, 200, 100);
appearance.setPageRect(rect);
appearance.setPageNumber(1);
signer.setFieldName("sig");
/* Set the document's certification level. This parameter defines if changes are allowed
* after the applying of the signature.
*/
signer.setCertificationLevel(certificationLevel);
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public void addText(String src, String dest) throws IOException {
PdfReader reader = new PdfReader(src);
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest), new StampingProperties().useAppendMode());
PdfPage firstPage = pdfDoc.getFirstPage();
new Canvas(firstPage, firstPage.getPageSize()).showTextAligned("TOP SECRET", 36, 820,
TextAlignment.LEFT);
pdfDoc.close();
}
public void addAnnotation(String src, String dest) throws IOException {
PdfReader reader = new PdfReader(src);
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest), new StampingProperties().useAppendMode());
PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
.setOpen(true)
.setIconName(new PdfName("Comment"))
.setTitle(new PdfString("Finally Signed!"))
.setContents("Bruno Specimen has finally signed the document");
pdfDoc.getFirstPage().addAnnotation(comment);
pdfDoc.close();
}
public void addWrongAnnotation(String src, String dest) throws IOException {
PdfReader reader = new PdfReader(src);
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest));
PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
.setOpen(true)
.setIconName(new PdfName("Comment"))
.setTitle(new PdfString("Finally Signed!"))
.setContents("Bruno Specimen has finally signed the document");
pdfDoc.getFirstPage().addAnnotation(comment);
pdfDoc.close();
}
public void signAgain(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setReuseAppearance(false);
Rectangle rect = new Rectangle(36, 700, 200, 100);
appearance.setPageRect(rect);
appearance.setPageNumber(1);
signer.setFieldName("Signature2");
PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws GeneralSecurityException, IOException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
C2_09_SignatureTypes app = new C2_09_SignatureTypes();
app.sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, PdfSigner.NOT_CERTIFIED,
"Test 1", "Ghent");
app.sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS,
"Test 1", "Ghent");
app.sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING,
"Test 1", "Ghent");
app.sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED,
"Test 1", "Ghent");
app.addAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[4]);
app.addAnnotation(DEST + RESULT_FILES[1], DEST + RESULT_FILES[5]);
app.addAnnotation(DEST + RESULT_FILES[2], DEST + RESULT_FILES[6]);
app.addAnnotation(DEST + RESULT_FILES[3], DEST + RESULT_FILES[7]);
app.addWrongAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[8]);
app.addText(DEST + RESULT_FILES[0], DEST + RESULT_FILES[9]);
app.signAgain(DEST + RESULT_FILES[0], DEST + RESULT_FILES[10], chain, pk,
DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
app.signAgain(DEST + RESULT_FILES[1], DEST + RESULT_FILES[11], chain, pk,
DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
app.signAgain(DEST + RESULT_FILES[2], DEST + RESULT_FILES[12], chain, pk,
DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
app.signAgain(DEST + RESULT_FILES[3], DEST + RESULT_FILES[13], chain, pk,
DigestAlgorithms.SHA256, provider.getName(),
PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Properties;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_09_SignatureTypes
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly string SRC = "../../../resources/pdfs/hello.pdf";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"hello_level_1.pdf", "hello_level_2.pdf",
"hello_level_3.pdf", "hello_level_4.pdf",
"hello_level_1_annotated.pdf", "hello_level_2_annotated.pdf",
"hello_level_3_annotated.pdf", "hello_level_4_annotated.pdf",
"hello_level_1_annotated_wrong.pdf", "hello_level_1_text.pdf",
"hello_level_1_double.pdf", "hello_level_2_double.pdf",
"hello_level_3_double.pdf", "hello_level_4_double.pdf",
};
public void Sign(String src, String dest, X509Certificate[] chain, ICipherParameters pk,
String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
int certificationLevel, String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
// Create the signature appearance
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
Rectangle rect = new Rectangle(36, 648, 200, 100);
appearance.SetPageRect(rect).SetPageNumber(1);
signer.SetFieldName("sig");
/* Set the document's certification level. This parameter defines if changes are allowed
* after the applying of the signature.
*/
signer.SetCertificationLevel(certificationLevel);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public void AddText(String src, String dest)
{
PdfReader reader = new PdfReader(src);
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest),
new StampingProperties().UseAppendMode());
PdfPage firstPage = pdfDoc.GetFirstPage();
new Canvas(firstPage, firstPage.GetPageSize()).ShowTextAligned("TOP SECRET",
36, 820, TextAlignment.LEFT);
pdfDoc.Close();
}
public void AddAnnotation(String src, String dest)
{
PdfReader reader = new PdfReader(src);
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest),
new StampingProperties().UseAppendMode());
PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
.SetOpen(true)
.SetIconName(new PdfName("Comment"))
.SetTitle(new PdfString("Finally Signed!"))
.SetContents("Bruno Specimen has finally signed the document");
pdfDoc.GetFirstPage().AddAnnotation(comment);
pdfDoc.Close();
}
public void AddWrongAnnotation(String src, String dest)
{
PdfReader reader = new PdfReader(src);
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest));
PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
.SetOpen(true)
.SetIconName(new PdfName("Comment"))
.SetTitle(new PdfString("Finally Signed!"))
.SetContents("Bruno Specimen has finally signed the document");
pdfDoc.GetFirstPage().AddAnnotation(comment);
pdfDoc.Close();
}
public void SignAgain(String src, String dest, X509Certificate[] chain, ICipherParameters pk,
String digestAlgorithm, PdfSigner.CryptoStandard subfilter, String reason, String location)
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason(reason);
appearance.SetLocation(location);
appearance.SetReuseAppearance(false);
Rectangle rect = new Rectangle(36, 700, 200, 100);
appearance.SetPageRect(rect).SetPageNumber(1);
signer.SetFieldName("Signature2");
IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
for (int i = 0; i < certificateWrappers.Length; ++i) {
certificateWrappers[i] = new X509CertificateBC(chain[i]);
}
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = ce[k].Certificate;
}
C2_09_SignatureTypes app = new C2_09_SignatureTypes();
app.Sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CMS, PdfSigner.NOT_CERTIFIED,
"Test 1", "Ghent");
app.Sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS,
"Test 1", "Ghent");
app.Sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING,
"Test 1", "Ghent");
app.Sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.SHA256,
PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED,
"Test 1", "Ghent");
app.AddAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[4]);
app.AddAnnotation(DEST + RESULT_FILES[1], DEST + RESULT_FILES[5]);
app.AddAnnotation(DEST + RESULT_FILES[2], DEST + RESULT_FILES[6]);
app.AddAnnotation(DEST + RESULT_FILES[3], DEST + RESULT_FILES[7]);
app.AddWrongAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[8]);
app.AddText(DEST + RESULT_FILES[0], DEST + RESULT_FILES[9]);
app.SignAgain(DEST + RESULT_FILES[0], DEST + RESULT_FILES[10], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Second signature test", "Gent");
app.SignAgain(DEST + RESULT_FILES[1], DEST + RESULT_FILES[11], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Second signature test", "Gent");
app.SignAgain(DEST + RESULT_FILES[2], DEST + RESULT_FILES[12], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Second signature test", "Gent");
app.SignAgain(DEST + RESULT_FILES[3], DEST + RESULT_FILES[13], chain, pk,
DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
"Second signature test", "Gent");
}
}
}
c2_10_sequentialsignatures
Sequential signatures in PDFs:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
public class C2_10_SequentialSignatures {
public static final String DEST = "./target/signatures/chapter02/";
public static final String FORM = "./target/signatures/chapter02/multiple_signatures.pdf";
public static final String ALICE = "./src/test/resources/encryption/alice";
public static final String BOB = "./src/test/resources/encryption/bob";
public static final String CAROL = "./src/test/resources/encryption/carol";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"signed_by_alice.pdf", "signed_by_bob.pdf",
"signed_by_carol.pdf", "signed_by_alice2.pdf",
"signed_by_bob2.pdf", "signed_by_carol2.pdf",
"signed_by_alice3.pdf", "signed_by_bob3.pdf",
"signed_by_carol3.pdf", "signed_by_alice4.pdf",
"signed_by_bob4.pdf", "signed_by_carol4.pdf",
};
public void createForm() throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
Document doc = new Document(pdfDoc);
Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
table.addCell("Signer 1: Alice");
table.addCell(createSignatureFieldCell("sig1"));
table.addCell("Signer 2: Bob");
table.addCell(createSignatureFieldCell("sig2"));
table.addCell("Signer 3: Carol");
table.addCell(createSignatureFieldCell("sig3"));
doc.add(table);
doc.close();
}
protected Cell createSignatureFieldCell(String name) {
Cell cell = new Cell();
cell.setHeight(50);
cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name));
return cell;
}
public void sign(String keystore, String provider, int level, String src, String name, String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
// Set the signer options
signer.setFieldName(name);
signer.setCertificationLevel(level);
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
C2_10_SequentialSignatures app = new C2_10_SequentialSignatures();
app.createForm();
/* Alice signs certification signature (allowing form filling),
* then Bob and Carol sign approval signature (not certified).
*/
app.sign(ALICE, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, FORM, "sig1", DEST + RESULT_FILES[0]);
app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[0], "sig2",
DEST + RESULT_FILES[1]);
app.sign(CAROL, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[1], "sig3",
DEST + RESULT_FILES[2]);
/* Alice signs approval signatures (not certified), so does Bob
* and then Carol signs certification signature allowing form filling.
*/
app.sign(ALICE, provider.getName(), PdfSigner.NOT_CERTIFIED, FORM, "sig1", DEST + RESULT_FILES[3]);
app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[3], "sig2",
DEST + RESULT_FILES[4]);
app.sign(CAROL, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[4], "sig3",
DEST + RESULT_FILES[5]);
/* Alice signs approval signatures (not certified), so does Bob
* and then Carol signs certification signature forbidding any changes to the document.
*/
app.sign(ALICE, provider.getName(), PdfSigner.NOT_CERTIFIED, FORM, "sig1", DEST + RESULT_FILES[6]);
app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[6], "sig2",
DEST + RESULT_FILES[7]);
app.sign(CAROL, provider.getName(), PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED, DEST + RESULT_FILES[7], "sig3",
DEST + RESULT_FILES[8]);
/* Alice signs certification signature (allowing form filling), then Bob signs approval
* signatures (not certified) and then Carol signs certification signature allowing form filling.
*/
app.sign(ALICE, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, FORM, "sig1", DEST + RESULT_FILES[9]);
app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[9], "sig2",
DEST + RESULT_FILES[10]);
app.sign(CAROL, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[10], "sig3",
DEST + RESULT_FILES[11]);
}
private static class SignatureFieldCellRenderer extends CellRenderer {
public String name;
public SignatureFieldCellRenderer(Cell modelElement, String name) {
super(modelElement);
this.name = name;
}
@Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
PdfFormField field = new SignatureFormFieldBuilder(drawContext.getDocument(), name)
.setWidgetRectangle(getOccupiedAreaBBox()).createSignature();
field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
field.getWidgets().get(0).setFlags(PdfAnnotation.PRINT);
PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
}
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_10_SequentialSignatures
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string FORM = "results/signatures/chapter02/multiple_signatures.pdf";
public static readonly string ALICE = "../../../resources/encryption/alice";
public static readonly string BOB = "../../../resources/encryption/bob";
public static readonly string CAROL = "../../../resources/encryption/carol";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"signed_by_alice.pdf", "signed_by_bob.pdf",
"signed_by_carol.pdf", "signed_by_alice2.pdf",
"signed_by_bob2.pdf", "signed_by_carol2.pdf",
"signed_by_alice3.pdf", "signed_by_bob3.pdf",
"signed_by_carol3.pdf", "signed_by_alice4.pdf",
"signed_by_bob4.pdf", "signed_by_carol4.pdf",
};
public void CreateForm()
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
Document doc = new Document(pdfDoc);
Table table = new Table(1).UseAllAvailableWidth();
table.AddCell("Signer 1: Alice");
table.AddCell(CreateSignatureFieldCell("sig1"));
table.AddCell("Signer 2: Bob");
table.AddCell(CreateSignatureFieldCell("sig2"));
table.AddCell("Signer 3: Carol");
table.AddCell(CreateSignatureFieldCell("sig3"));
doc.Add(table);
doc.Close();
}
protected Cell CreateSignatureFieldCell(String name)
{
Cell cell = new Cell();
cell.SetHeight(50);
cell.SetNextRenderer(new SignatureFieldCellRenderer(cell, name));
return cell;
}
public void Sign(String keystore, int level, String src, String name, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
// Set the signer options
signer.SetFieldName(name);
signer.SetCertificationLevel(level);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, chain, null, null, null, 0,
PdfSigner.CryptoStandard.CMS);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
C2_10_SequentialSignatures app = new C2_10_SequentialSignatures();
app.CreateForm();
/* Alice signs certification signature (allowing form filling),
* then Bob and Carol sign approval signature (not certified).
*/
app.Sign(ALICE, PdfSigner.CERTIFIED_FORM_FILLING, FORM,
"sig1", DEST + RESULT_FILES[0]);
app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[0],
"sig2", DEST + RESULT_FILES[1]);
app.Sign(CAROL, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[1],
"sig3", DEST + RESULT_FILES[2]);
/* Alice signs approval signatures (not certified), so does Bob
* and then Carol signs certification signature allowing form filling.
*/
app.Sign(ALICE, PdfSigner.NOT_CERTIFIED, FORM,
"sig1", DEST + RESULT_FILES[3]);
app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[3],
"sig2", DEST + RESULT_FILES[4]);
app.Sign(CAROL, PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[4],
"sig3", DEST + RESULT_FILES[5]);
/* Alice signs approval signatures (not certified), so does Bob
* and then Carol signs certification signature forbidding any changes to the document.
*/
app.Sign(ALICE, PdfSigner.NOT_CERTIFIED, FORM,
"sig1", DEST + RESULT_FILES[6]);
app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[6],
"sig2", DEST + RESULT_FILES[7]);
app.Sign(CAROL, PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED, DEST + RESULT_FILES[7],
"sig3", DEST + RESULT_FILES[8]);
/* Alice signs certification signature (allowing form filling), then Bob signs approval
* signatures (not certified) and then Carol signs certification signature allowing form filling.
*/
app.Sign(ALICE, PdfSigner.CERTIFIED_FORM_FILLING, FORM,
"sig1", DEST + RESULT_FILES[9]);
app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[9],
"sig2", DEST + RESULT_FILES[10]);
app.Sign(CAROL, PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[10],
"sig3", DEST + RESULT_FILES[11]);
}
private class SignatureFieldCellRenderer : CellRenderer
{
public String name;
public SignatureFieldCellRenderer(Cell modelElement, String name)
: base(modelElement)
{
this.name = name;
}
public override void Draw(DrawContext drawContext)
{
base.Draw(drawContext);
PdfFormField field = new SignatureFormFieldBuilder(drawContext.GetDocument(), name)
.SetWidgetRectangle(GetOccupiedAreaBBox()).CreateSignature();
field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
field.GetWidgets()[0].SetFlags(PdfAnnotation.PRINT);
PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
}
}
}
}
c2_11_signatureworkflow
An example where multiple signatures are required:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.forms.fields.TextFormFieldBuilder;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
public class C2_11_SignatureWorkflow {
public static final String DEST = "./target/signatures/chapter02/";
public static final String FORM = "./target/signatures/chapter02/form.pdf";
public static final String ALICE = "./src/test/resources/encryption/alice";
public static final String BOB = "./src/test/resources/encryption/bob";
public static final String CAROL = "./src/test/resources/encryption/carol";
public static final String DAVE = "./src/test/resources/encryption/dave";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"step1_signed_by_alice.pdf", "step2_signed_by_alice_and_filled_out_by_bob.pdf",
"step3_signed_by_alice_and_bob.pdf", "step4_signed_by_alice_and_bob_filled_out_by_carol.pdf",
"step5_signed_by_alice_bob_and_carol.pdf", "step6_signed_by_alice_bob_carol_and_dave.pdf"
};
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
C2_11_SignatureWorkflow app = new C2_11_SignatureWorkflow();
app.createForm();
String aliceCertifiedFile = DEST + RESULT_FILES[0];
app.certify(ALICE, provider.getName(), FORM, "sig1", aliceCertifiedFile);
String bobFilledFile = DEST + RESULT_FILES[1];
String bobSignedFile = DEST + RESULT_FILES[2];
app.fillOut(aliceCertifiedFile, bobFilledFile,
"approved_bob", "Read and Approved by Bob");
app.sign(BOB, provider.getName(), bobFilledFile, "sig2",
bobSignedFile);
String carolFilledFile = DEST + RESULT_FILES[3];
String carolSignedFile = DEST + RESULT_FILES[4];
app.fillOut(bobSignedFile, carolFilledFile,
"approved_carol", "Read and Approved by Carol");
app.sign(CAROL, provider.getName(), carolFilledFile, "sig3",
carolSignedFile);
String daveFilledCertifiedFile = DEST + RESULT_FILES[5];
app.fillOutAndSign(DAVE, provider.getName(), carolSignedFile, "sig4",
"approved_dave", "Read and Approved by Dave", daveFilledCertifiedFile);
}
public void createForm() throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
Document doc = new Document(pdfDoc);
Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
table.addCell("Written by Alice");
table.addCell(createSignatureFieldCell("sig1"));
table.addCell("For approval by Bob");
table.addCell(createTextFieldCell("approved_bob"));
table.addCell(createSignatureFieldCell("sig2"));
table.addCell("For approval by Carol");
table.addCell(createTextFieldCell("approved_carol"));
table.addCell(createSignatureFieldCell("sig3"));
table.addCell("For approval by Dave");
table.addCell(createTextFieldCell("approved_dave"));
table.addCell(createSignatureFieldCell("sig4"));
doc.add(table);
doc.close();
}
public void certify(String keystore, String provider, String src, String name, String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
// Set signer options
signer.setFieldName(name);
signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
}
public void fillOut(String src, String dest, String name, String value) throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
new StampingProperties().useAppendMode());
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
form.getField(name).setValue(value);
form.getField(name).setReadOnly(true);
pdfDoc.close();
}
public void sign(String keystore, String provider, String src, String name, String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
signer.setFieldName(name);
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
}
public void fillOutAndSign(String keystore, String provider, String src, String name, String fname, String value,
String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
signer.setFieldName(name);
PdfAcroForm form = PdfAcroForm.getAcroForm(signer.getDocument(), true);
form.getField(fname).setValue(value);
form.getField(fname).setReadOnly(true);
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
}
protected static Cell createTextFieldCell(String name) {
Cell cell = new Cell();
cell.setHeight(20);
cell.setNextRenderer(new TextFieldCellRenderer(cell, name));
return cell;
}
protected static Cell createSignatureFieldCell(String name) {
Cell cell = new Cell();
cell.setHeight(50);
cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name));
return cell;
}
private static class TextFieldCellRenderer extends CellRenderer {
public String name;
public TextFieldCellRenderer(Cell modelElement, String name) {
super(modelElement);
this.name = name;
}
@Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
PdfFormField field = new TextFormFieldBuilder(drawContext.getDocument(), name)
.setWidgetRectangle(getOccupiedAreaBBox()).createText();
PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
}
}
private static class SignatureFieldCellRenderer extends CellRenderer {
public String name;
public SignatureFieldCellRenderer(Cell modelElement, String name) {
super(modelElement);
this.name = name;
}
@Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
PdfFormField field = new SignatureFormFieldBuilder(drawContext.getDocument(), name)
.setWidgetRectangle(getOccupiedAreaBBox()).createSignature();
field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
field.getWidgets().get(0).setFlags(PdfAnnotation.PRINT);
PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
}
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_11_SignatureWorkflow
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string FORM = "results/signatures/chapter02/form.pdf";
public static readonly string ALICE = "../../../resources/encryption/alice";
public static readonly string BOB = "../../../resources/encryption/bob";
public static readonly string CAROL = "../../../resources/encryption/carol";
public static readonly string DAVE = "../../../resources/encryption/dave";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"step1_signed_by_alice.pdf", "step2_signed_by_alice_and_filled_out_by_bob.pdf",
"step3_signed_by_alice_and_bob.pdf", "step4_signed_by_alice_and_bob_filled_out_by_carol.pdf",
"step5_signed_by_alice_bob_and_carol.pdf", "step6_signed_by_alice_bob_carol_and_dave.pdf"
};
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
C2_11_SignatureWorkflow app = new C2_11_SignatureWorkflow();
app.CreateForm();
String aliceCertifiedFile = DEST + RESULT_FILES[0];
app.Certify(ALICE, FORM, "sig1", aliceCertifiedFile);
String bobFilledFile = DEST + RESULT_FILES[1];
String bobSignedFile = DEST + RESULT_FILES[2];
app.FillOut(aliceCertifiedFile, bobFilledFile, "approved_bob", "Read and Approved by Bob");
app.Sign(BOB, bobFilledFile, "sig2", bobSignedFile);
String carolFilledFile = DEST + RESULT_FILES[3];
String carolSignedFile = DEST + RESULT_FILES[4];
app.FillOut(bobSignedFile, carolFilledFile, "approved_carol", "Read and Approved by Carol");
app.Sign(CAROL, carolFilledFile, "sig3", carolSignedFile);
String daveFilledCertifiedFile = DEST + RESULT_FILES[5];
app.FillOutAndSign(DAVE, carolSignedFile, "sig4", "approved_dave",
"Read and Approved by Dave", daveFilledCertifiedFile);
}
public void CreateForm()
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
Document doc = new Document(pdfDoc);
Table table = new Table(1).UseAllAvailableWidth();
table.AddCell("Written by Alice");
table.AddCell(CreateSignatureFieldCell("sig1"));
table.AddCell("For approval by Bob");
table.AddCell(CreateTextFieldCell("approved_bob"));
table.AddCell(CreateSignatureFieldCell("sig2"));
table.AddCell("For approval by Carol");
table.AddCell(CreateTextFieldCell("approved_carol"));
table.AddCell(CreateSignatureFieldCell("sig3"));
table.AddCell("For approval by Dave");
table.AddCell(CreateTextFieldCell("approved_dave"));
table.AddCell(CreateSignatureFieldCell("sig4"));
doc.Add(table);
doc.Close();
}
public void Certify(String keystore, String src, String name, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
// Set signer options
signer.SetFieldName(name);
signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
}
public void FillOut(String src, String dest, String name, String value)
{
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
new StampingProperties().UseAppendMode());
PdfAcroForm form = PdfFormCreator.GetAcroForm(pdfDoc, true);
form.GetField(name).SetValue(value);
form.GetField(name).SetReadOnly(true);
pdfDoc.Close();
}
public virtual void Sign(String keystore, String src, String name, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
signer.SetFieldName(name);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
signer.SignDetached(pks, chain, null, null, null, 0,
PdfSigner.CryptoStandard.CMS);
}
public void FillOutAndSign(String keystore, String src, String name, String fname,
String value, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
signer.SetFieldName(name);
PdfAcroForm form = PdfFormCreator.GetAcroForm(signer.GetDocument(), true);
form.GetField(fname).SetValue(value);
form.GetField(fname).SetReadOnly(true);
IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
signer.SignDetached(pks, chain, null, null, null, 0,
PdfSigner.CryptoStandard.CMS);
}
protected static Cell CreateTextFieldCell(String name)
{
Cell cell = new Cell();
cell.SetHeight(20);
cell.SetNextRenderer(new TextFieldCellRenderer(cell, name));
return cell;
}
protected static Cell CreateSignatureFieldCell(String name)
{
Cell cell = new Cell();
cell.SetHeight(50);
cell.SetNextRenderer(new SignatureFieldCellRenderer(cell, name));
return cell;
}
private class TextFieldCellRenderer : CellRenderer
{
public String name;
public TextFieldCellRenderer(Cell modelElement, String name)
: base(modelElement)
{
this.name = name;
}
public override void Draw(DrawContext drawContext)
{
base.Draw(drawContext);
PdfFormField field = new TextFormFieldBuilder(drawContext.GetDocument(), name)
.SetWidgetRectangle(GetOccupiedAreaBBox()).CreateText();
PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
}
}
private class SignatureFieldCellRenderer : CellRenderer
{
public String name;
public SignatureFieldCellRenderer(Cell modelElement, String name)
: base(modelElement)
{
this.name = name;
}
public override void Draw(DrawContext drawContext)
{
base.Draw(drawContext);
PdfFormField field = new SignatureFormFieldBuilder(drawContext.GetDocument(), name)
.SetWidgetRectangle(GetOccupiedAreaBBox()).CreateSignature();
field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
field.GetWidgets()[0].SetFlags(PdfAnnotation.PRINT);
PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
}
}
}
}
c2_12_lockfields
Locking fields and documents after signing:
JAVA
package com.itextpdf.samples.signatures.chapter02;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.PdfSigFieldLock;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.forms.fields.TextFormFieldBuilder;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.File;
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.Security;
import java.security.cert.Certificate;
public class C2_12_LockFields {
public static final String DEST = "./target/signatures/chapter02/";
public static final String FORM = "./target/signatures/chapter02/form_lock.pdf";
public static final String ALICE = "./src/test/resources/encryption/alice";
public static final String BOB = "./src/test/resources/encryption/bob";
public static final String CAROL = "./src/test/resources/encryption/carol";
public static final String DAVE = "./src/test/resources/encryption/dave";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"step_1_signed_by_alice.pdf", "step_2_signed_by_alice_and_bob.pdf",
"step_3_signed_by_alice_bob_and_carol.pdf", "step_4_signed_by_alice_bob_carol_and_dave.pdf",
"step_5_signed_by_alice_and_bob_broken_by_chuck.pdf", "step_6_signed_by_dave_broken_by_chuck.pdf"
};
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
C2_12_LockFields app = new C2_12_LockFields();
app.createForm();
app.certify(ALICE, provider.getName(), FORM, "sig1", DEST + RESULT_FILES[0]);
app.fillOutAndSign(BOB, provider.getName(), DEST + RESULT_FILES[0], "sig2", "approved_bob",
"Read and Approved by Bob", DEST + RESULT_FILES[1]);
app.fillOutAndSign(CAROL, provider.getName(), DEST + RESULT_FILES[1], "sig3", "approved_carol",
"Read and Approved by Carol", DEST + RESULT_FILES[2]);
app.fillOutAndSign(DAVE, provider.getName(), DEST + RESULT_FILES[2], "sig4", "approved_dave",
"Read and Approved by Dave", DEST + RESULT_FILES[3]);
app.fillOut(DEST + RESULT_FILES[1], DEST + RESULT_FILES[4],
"approved_bob", "Changed by Chuck");
app.fillOut(DEST + RESULT_FILES[3], DEST + RESULT_FILES[5],
"approved_carol", "Changed by Chuck");
}
public void createForm() throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
Document doc = new Document(pdfDoc);
Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
table.addCell("Written by Alice");
table.addCell(createSignatureFieldCell("sig1", null));
table.addCell("For approval by Bob");
table.addCell(createTextFieldCell("approved_bob"));
PdfSigFieldLock lock = new PdfSigFieldLock()
.setFieldLock(PdfSigFieldLock.LockAction.INCLUDE, "sig1", "approved_bob", "sig2");
table.addCell(createSignatureFieldCell("sig2", lock));
table.addCell("For approval by Carol");
table.addCell(createTextFieldCell("approved_carol"));
lock = new PdfSigFieldLock().setFieldLock(PdfSigFieldLock.LockAction.EXCLUDE, "approved_dave", "sig4");
table.addCell(createSignatureFieldCell("sig3", lock));
table.addCell("For approval by Dave");
table.addCell(createTextFieldCell("approved_dave"));
lock = new PdfSigFieldLock().setDocumentPermissions(PdfSigFieldLock.LockPermissions.NO_CHANGES_ALLOWED);
table.addCell(createSignatureFieldCell("sig4", lock));
doc.add(table);
doc.close();
}
public void certify(String keystore, String provider, String src, String name, String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
// Set signer options
signer.setFieldName(name);
signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);
PdfAcroForm form = PdfAcroForm.getAcroForm(signer.getDocument(), true);
form.getField(name).setReadOnly(true);
PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.signDetached(digest, pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
public void fillOutAndSign(String keystore, String provider, String src, String name, String fname, String value,
String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
signer.setFieldName(name);
PdfAcroForm form = PdfAcroForm.getAcroForm(signer.getDocument(), true);
form.getField(fname).setValue(value);
form.getField(name).setReadOnly(true);
form.getField(fname).setReadOnly(true);
PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
public void fillOut(String src, String dest, String name, String value) throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
new StampingProperties().useAppendMode());
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
form.getField(name).setValue(value);
pdfDoc.close();
}
public void sign(String keystore, String provider, String src, String name, String dest)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), PASSWORD);
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
signer.setFieldName(name);
PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
protected static Cell createTextFieldCell(String name) {
Cell cell = new Cell();
cell.setHeight(20);
cell.setNextRenderer(new TextFieldCellRenderer(cell, name));
return cell;
}
protected static Cell createSignatureFieldCell(String name, PdfSigFieldLock lock) {
Cell cell = new Cell();
cell.setHeight(50);
cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name, lock));
return cell;
}
private static class TextFieldCellRenderer extends CellRenderer {
public String name;
public TextFieldCellRenderer(Cell modelElement, String name) {
super(modelElement);
this.name = name;
}
@Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
PdfFormField field = new TextFormFieldBuilder(drawContext.getDocument(), name)
.setWidgetRectangle(getOccupiedAreaBBox()).createText();
PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
}
}
private static class SignatureFieldCellRenderer extends CellRenderer {
public String name;
public PdfSigFieldLock lock;
public SignatureFieldCellRenderer(Cell modelElement, String name, PdfSigFieldLock lock) {
super(modelElement);
this.name = name;
this.lock = lock;
}
@Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
PdfFormField field = new SignatureFormFieldBuilder(drawContext.getDocument(), name)
.setWidgetRectangle(getOccupiedAreaBBox()).createSignature();
if (lock != null) {
field.put(PdfName.Lock, lock.makeIndirect(drawContext.getDocument()).getPdfObject());
}
field.getWidgets().get(0).setFlag(PdfAnnotation.PRINT);
field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
}
}
}
C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
namespace iText.Samples.Signatures.Chapter02
{
public class C2_12_LockFields
{
public static readonly string DEST = "results/signatures/chapter02/";
public static readonly string FORM = "results/signatures/chapter02/form_lock.pdf";
public static readonly string ALICE = "../../../resources/encryption/alice";
public static readonly string BOB = "../../../resources/encryption/bob";
public static readonly string CAROL = "../../../resources/encryption/carol";
public static readonly string DAVE = "../../../resources/encryption/dave";
public static readonly string KEYSTORE = "../../../resources/encryption/ks";
public static readonly char[] PASSWORD = "password".ToCharArray();
public static readonly String[] RESULT_FILES =
{
"step_1_signed_by_alice.pdf", "step_2_signed_by_alice_and_bob.pdf",
"step_3_signed_by_alice_bob_and_carol.pdf", "step_4_signed_by_alice_bob_carol_and_dave.pdf",
"step_5_signed_by_alice_and_bob_broken_by_chuck.pdf", "step_6_signed_by_dave_broken_by_chuck.pdf"
};
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
C2_12_LockFields app = new C2_12_LockFields();
app.CreateForm();
app.Certify(ALICE, FORM, "sig1", DEST + RESULT_FILES[0]);
app.FillOutAndSign(BOB, DEST + RESULT_FILES[0], "sig2", "approved_bob",
"Read and Approved by Bob", DEST + RESULT_FILES[1]);
app.FillOutAndSign(CAROL, DEST + RESULT_FILES[1], "sig3", "approved_carol",
"Read and Approved by Carol", DEST + RESULT_FILES[2]);
app.FillOutAndSign(DAVE, DEST + RESULT_FILES[2], "sig4", "approved_dave",
"Read and Approved by Dave", DEST + RESULT_FILES[3]);
app.FillOut(DEST + RESULT_FILES[1], DEST + RESULT_FILES[4],
"approved_bob", "Changed by Chuck");
app.FillOut(DEST + RESULT_FILES[3], DEST + RESULT_FILES[5],
"approved_carol", "Changed by Chuck");
}
public void CreateForm()
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
Document doc = new Document(pdfDoc);
Table table = new Table(1).UseAllAvailableWidth();
table.AddCell("Written by Alice");
table.AddCell(CreateSignatureFieldCell("sig1", null));
table.AddCell("For approval by Bob");
table.AddCell(CreateTextFieldCell("approved_bob"));
PdfSigFieldLock Lock = new PdfSigFieldLock().SetFieldLock(PdfSigFieldLock.LockAction.INCLUDE,
"sig1", "approved_bob", "sig2");
table.AddCell(CreateSignatureFieldCell("sig2", Lock));
table.AddCell("For approval by Carol");
table.AddCell(CreateTextFieldCell("approved_carol"));
Lock = new PdfSigFieldLock().SetFieldLock(PdfSigFieldLock.LockAction.EXCLUDE,
"approved_dave", "sig4");
table.AddCell(CreateSignatureFieldCell("sig3", Lock));
table.AddCell("For approval by Dave");
table.AddCell(CreateTextFieldCell("approved_dave"));
Lock = new PdfSigFieldLock().SetDocumentPermissions(PdfSigFieldLock.LockPermissions.NO_CHANGES_ALLOWED);
table.AddCell(CreateSignatureFieldCell("sig4", Lock));
doc.Add(table);
doc.Close();
}
public void Certify(String keystore, String src, String name, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
// Set signer options
signer.SetFieldName(name);
signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);
PdfAcroForm form = PdfFormCreator.GetAcroForm(signer.GetDocument(), true);
form.GetField(name).SetReadOnly(true);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
// Sign the document using the detached mode, CMS or CAdES equivalent.
signer.SignDetached(pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
public void FillOutAndSign(String keystore, String src, String name, String fname, String value, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
signer.SetFieldName(name);
PdfAcroForm form = PdfFormCreator.GetAcroForm(signer.GetDocument(), true);
form.GetField(fname).SetValue(value);
form.GetField(name).SetReadOnly(true);
form.GetField(fname).SetReadOnly(true);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
signer.SignDetached(pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
public void FillOut(String src, String dest, String name, String value)
{
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
new StampingProperties().UseAppendMode());
PdfAcroForm form = PdfFormCreator.GetAcroForm(pdfDoc, true);
form.GetField(name).SetValue(value);
pdfDoc.Close();
}
public void Sign(String keystore, String src, String name, String dest)
{
Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
string alias = null;
foreach (var a in pk12.Aliases)
{
alias = ((string) a);
if (pk12.IsKeyEntry(alias))
break;
}
ICipherParameters pk = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
IX509Certificate[] chain = new IX509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
{
chain[k] = new X509CertificateBC(ce[k].Certificate);
}
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
new StampingProperties().UseAppendMode());
signer.SetFieldName(name);
PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
signer.SignDetached(pks, chain, null, null, null,
0, PdfSigner.CryptoStandard.CMS);
}
protected static Cell CreateTextFieldCell(String name)
{
Cell cell = new Cell();
cell.SetHeight(20);
cell.SetNextRenderer(new TextFieldCellRenderer(cell, name));
return cell;
}
protected static Cell CreateSignatureFieldCell(String name, PdfSigFieldLock Lock)
{
Cell cell = new Cell();
cell.SetHeight(50);
cell.SetNextRenderer(new SignatureFieldCellRenderer(cell, name, Lock));
return cell;
}
private class TextFieldCellRenderer : CellRenderer
{
public String name;
public TextFieldCellRenderer(Cell modelElement, String name)
: base(modelElement)
{
this.name = name;
}
public override void Draw(DrawContext drawContext)
{
base.Draw(drawContext);
PdfFormField field = new TextFormFieldBuilder(drawContext.GetDocument(), name)
.SetWidgetRectangle(GetOccupiedAreaBBox()).CreateText();
PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
}
}
private class SignatureFieldCellRenderer : CellRenderer
{
public String name;
public PdfSigFieldLock Lock;
public SignatureFieldCellRenderer(Cell modelElement, String name, PdfSigFieldLock Lock)
: base(modelElement)
{
this.name = name;
this.Lock = Lock;
}
public override void Draw(DrawContext drawContext)
{
base.Draw(drawContext);
PdfFormField field = new SignatureFormFieldBuilder(drawContext.GetDocument(), name)
.SetWidgetRectangle(GetOccupiedAreaBBox()).CreateSignature();
if (Lock != null)
{
field.Put(PdfName.Lock, this.Lock.MakeIndirect(drawContext.GetDocument()).GetPdfObject());
}
field.GetWidgets()[0].SetFlag(PdfAnnotation.PRINT);
field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
}
}
}
}