我正在动态创建PDF文档,添加签名字段,然后尝试签名。签名工作正常,但我得到一个例外:
“由%认证,无效签名和签名包含无效数据”
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Calendar;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
//Actual class
public class SignPdf {
// Signs the pdf
public void signPdf(String src, String dest, boolean certified, boolean graphic) throws GeneralSecurityException, IOException, DocumentException{
String path = "src/certs.pfx";
String keystore_password = "pwd";
String key_password = "pwd";
KeyStore ks = KeyStore.getInstance("PKCS12", new org.bouncycastle.jce.provider.BouncyCastleProvider());
InputStream is = this.getClass().getResourceAsStream("/certs.pfx");
ks.load(is, keystore_password.toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
byte[] pdfByteArray = null;
// creating dynamic document using itext.
Document document = new Document();
OutputStream baosPDF = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baosPDF);
document.open();
document.add(new Paragraph("Hello World!"));
document.close();
byte[] bytearrayb = ((ByteArrayOutputStream) baosPDF).toByteArray();
PdfReader reader = new PdfReader(bytearrayb);
PdfStamper stamper = PdfStamper.createSignature(reader, baosPDF, '\0', null, true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason("Security");
appearance.setLocation("Footer");
appearance.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, "DVA");
if (certified) appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
if (graphic) {
appearance.setSignatureGraphic(Image.getInstance(RESOURCE));
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
}
appearance.setSignDate(Calendar.getInstance());
appearance.setSignatureCreator("test");
ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);
baosPDF.flush();
baosPDF.close();
BufferedOutputStream fs = new BufferedOutputStream(new FileOutputStream(new File("myFile121.pdf")));
fs.write(((ByteArrayOutputStream) baosPDF).toByteArray());
fs.flush();
fs.close();
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
SignPdf signatures = new SignPdf();
try {
signatures.signPdf(ORIGINAL, "", true, false);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
答案 0 :(得分:1)
您可以重新使用ByteArrayOutputStream
而不清除它:
OutputStream baosPDF = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baosPDF);
document.open();
document.add(new Paragraph("Hello World!"));
document.close();
byte[] bytearrayb = ((ByteArrayOutputStream) baosPDF).toByteArray();
PdfReader reader = new PdfReader(bytearrayb);
PdfStamper stamper = PdfStamper.createSignature(reader, baosPDF, '\0', null, true);
根据ByteArrayOutputStream
来源:
/**
* Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* @see java.io.ByteArrayInputStream#count
*/
public synchronized void reset()
因此,在重新使用前重置:
byte[] bytearrayb = ((ByteArrayOutputStream) baosPDF).toByteArray();
baosPDF.reset();
PdfReader reader = new PdfReader(bytearrayb);
PdfStamper stamper = PdfStamper.createSignature(reader, baosPDF, '\0', null, true);