【发布时间】:2021-02-22 12:17:18
【问题描述】:
我已经部分阅读了itextpdf's paper 关于数字签名的内容,并从中开始开发我的代码:
public class ServerSignature implements ExternalSignature {
public String getHashAlgorithm() {
return DigestAlgorithms.SHA256;
}
public String getEncryptionAlgorithm() {
return "RSA";
}
public byte[] sign(byte[] message) throws GeneralSecurityException {
byte[] s = Base64.getDecoder().decode(SPMService.this.signature);
return s;
}
}
public void sign(Certificate[] chain, CryptoStandard subfilter, String reason,
String location) throws GeneralSecurityException, DocumentException, IOException {
// Creating the reader and the stamper
System.out.println("SRC: " + this.SRC);
PdfReader reader = new PdfReader(this.SRC);
FileOutputStream os = new FileOutputStream(this.DEST);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new ServerSignature();
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
this.verifySignatures(this.DEST);
}
private void verifySignature(AcroFields fields, String name) throws GeneralSecurityException, IOException {
// Returns true
System.out.println("Signature covers whole document: " + fields.signatureCoversWholeDocument(name));
// Returns the right revisions, e.g. 1 of 1
System.out.println("Document revision: " + fields.getRevision(name) + " of " + fields.getTotalRevisions());
PdfPKCS7 pkcs7 = fields.verifySignature(name);
// Returns SHA256
System.out.println("Digest algorithm: " + pkcs7.getHashAlgorithm());
//Returns RSA
System.out.println("Encryption algorithm: " + pkcs7.getEncryptionAlgorithm());
// Return /adbe.pkcs7.detached
System.out.println("Filter subtype: " + pkcs7.getFilterSubtype());
// Get the signing certificate to find out the name of the signer.
X509Certificate cert = (X509Certificate) pkcs7.getSigningCertificate();
System.out.println("Name of the signer: " + CertificateInfo.getSubjectFields(cert).getField("CN"));
if (pkcs7.getSignName() != null) {
System.out.println("Alternative name of the signer: " + pkcs7.getSignName());
}
// The following log is returning false always. Why?
System.out.println("Integrity check OK? " + pkcs7.verify());
}
private void verifySignatures(String src) throws IOException, GeneralSecurityException {
Security.addProvider(new BouncyCastleProvider());
PdfReader reader = new PdfReader(src);
AcroFields fields = reader.getAcroFields();
ArrayList<String> names = fields.getSignatureNames();
for (String name : names) {
System.out.println("===== " + name + " =====");
verifySignature(fields, name);
}
System.out.println();
}
public void start() throws GeneralSecurityException, DocumentException, IOException {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
// certificate I received in the Controller
InputStream targetStream = new ByteArrayInputStream(this.certificate.getBytes());
Certificate[] chain = new Certificate[1];
chain[0] = factory.generateCertificate(targetStream);
this.sign(chain, CryptoStandard.CMS, "Reason", "Location");
}
使用此代码,当我使用 Adobe Acrobat Reader 打开已签名的文档时,签名可见并且嵌入在文档中。问题是它带有一个红色标记,表明“文档自签署以来已被更改或损坏”。
有人可以向我解释缺少什么或者我的逻辑是否错误?
【问题讨论】:
-
请分享一个由您的代码签名的示例 PDF 以供分析。
-
ServerSignature中似乎有一个错误:在嵌入式签名容器中,签名字节签署了错误的哈希值(不是签名属性的哈希值,而是其他一些值)。 -
你能给我举个例子吗?
-
“你能给我举个例子吗” - 一个什么例子?我刚刚写了一个答案,其中包含有关您的示例 PDF 分析的更多详细信息。
标签: java itext digital-signature