Java 使用iText 5对已签名文档进行数字签名
嗨,我能用iText 5对a进行数字签名。我有一个再次签署PDF的要求,而在验证PDF时,它表明初始签名无效。您可以查看已重新签名的文件 请参见下面用于标记的代码Java 使用iText 5对已签名文档进行数字签名,java,itext,digital-signature,Java,Itext,Digital Signature,嗨,我能用iText 5对a进行数字签名。我有一个再次签署PDF的要求,而在验证PDF时,它表明初始签名无效。您可以查看已重新签名的文件 请参见下面用于标记的代码 import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.K
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import com.itextpdf.text.DocumentException;
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.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.PrivateKeySignature;
public class Test {
public static void main(String[] args) throws DocumentException, IOException, GeneralSecurityException {
PdfReader reader = null;
PrivateKey pk = null;
String alias = "PRASANTH KARUNAKARAN NAIR";
KeyStore ks = null;
try {
ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
}
catch (KeyStoreException|java.security.NoSuchProviderException e4){
e4.printStackTrace();
}
try {
ks.load(null, null);
}
catch (NoSuchAlgorithmException|java.security.cert.CertificateException|IOException e4){
e4.printStackTrace();
}
try {
pk = (PrivateKey)ks.getKey(alias, "abcd".toCharArray());
}
catch (UnrecoverableKeyException|KeyStoreException|NoSuchAlgorithmException e3){
e3.printStackTrace();
}
Certificate[] chain = null;
try {
chain = ks.getCertificateChain(alias);
}
catch (KeyStoreException e3){
e3.printStackTrace();
}
try {
reader = new PdfReader("D:///signedSample.pdf");
}
catch (IOException e5){
e5.printStackTrace();
}
String signedFileNameWithPath = "D:///signedsignedSample.pdf";
FileOutputStream os = null;
try {
os = new FileOutputStream(signedFileNameWithPath);
}
catch (FileNotFoundException e5){
e5.printStackTrace();
}
PdfStamper stamper = null;
try {
stamper = PdfStamper.createSignature(reader, os,'\0');
}
catch (DocumentException|IOException e5) {
e5.printStackTrace();
}
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
Integer pageNumber = 2;
Rectangle rect=new Rectangle(50,100,220,140);
appearance.setAcro6Layers(false);
appearance.setLayer4Text(PdfSignatureAppearance.questionMark);
appearance.setVisibleSignature(rect,pageNumber, "sig2");
PrivateKeySignature privateKeySignature=null;
try {
privateKeySignature= new PrivateKeySignature(pk, "SHA-256", ks.getProvider().getName());
}
catch (NullPointerException e) {
}
if(privateKeySignature!=null) {
BouncyCastleDigest bouncyCastleDigest = new BouncyCastleDigest();
try {
MakeSignature.signDetached(appearance, (ExternalDigest)bouncyCastleDigest, (ExternalSignature)privateKeySignature, chain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
}
catch (IOException e1){
e1.printStackTrace();
}
catch (DocumentException e1){
e1.printStackTrace();
}
catch (SignatureException e1) {
e1.printStackTrace();
}
catch (GeneralSecurityException e1){
e1.printStackTrace();
}
}
}
}
请告诉我出了什么问题。如果您想在已签名的PDF中添加另一个签名,显然必须小心,不要更改任何已签名的字节。换句话说,添加和更改必须作为增量更新附加到现有文件中 例如,具有三个签名的PDF的示意图必须与以下内容类似: (对于背景和引用的文档,请阅读。) 但是,默认情况下,iText
PdfStamper
不使用增量更新,而是使用原始文件中的单个对象以可能完全更改的顺序创建一个全新的文件,并且删除的对象在新版本中不再需要。这当然会导致第一个签名无效
要创建使用增量更新的PdfStamper
,必须使用不同的PdfStamper.createSignature
重载。请更换
stamper = PdfStamper.createSignature(reader, os,'\0');
借
额外的参数在方法JavaDocs中记录如下:
/* @param reader the original document
* @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
* @param pdfVersion the new pdf version or '\0' to keep the same version as the original
* document
* @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
* If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
* In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
* no temporary file will be created and memory will be used
* @param append if <CODE>true</CODE> the signature and all the other content will be added as a
* new revision thus not invalidating existing signatures
另一方面,捕获异常、打印它们各自的堆栈跟踪,然后像什么都没发生一样继续下去,最终会在生产中惨遭失败。将避免在生产中使用。谢谢你的反馈。
/* @param reader the original document
* @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
* @param pdfVersion the new pdf version or '\0' to keep the same version as the original
* document
* @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
* If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
* In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
* no temporary file will be created and memory will be used
* @param append if <CODE>true</CODE> the signature and all the other content will be added as a
* new revision thus not invalidating existing signatures