Meh*_*hdi 4 java digital-signature pdfbox
我正在尝试使用 DSS 签署 PDF 文档,但我的问题是我无法在服务器 A 中计算文档的哈希值,然后在服务器 B 中对其进行签名。
知道服务器 A 包含 PDF 文档,并且在服务器 B 中我们检索用于签名的证书
我的问题是如何在不需要证书的情况下计算服务器 A 中文档的哈希值。然后发送到服务器B请求签名?
更新 :
****** 哈希的准备和计算 ********
IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
PAdESSignatureParameters parameters = new PAdESSignatureParameters();
parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
parameters.setReason("Preuve de signature");
parameters.setLocation("MAROC");
parameters.setGenerateTBSWithoutCertificate(true);
SignatureImageParameters imageParameters = new SignatureImageParameters();
imageParameters.setPage(1);
FileDocument imageFile = new FileDocument("logo.png");
RemoteDocument fileImage = RemoteDocumentConverter.toRemoteDocument(imageFile);
DSSDocument image = RemoteDocumentConverter.toDSSDocument(fileImage);
// set an image
imageParameters.setImage(image);
imageParameters.setxAxis(350);
imageParameters.setyAxis(400);
imageParameters.setWidth(200);
imageParameters.setHeight(100);
parameters.setImageParameters(imageParameters);
SignatureImageTextParameters textParameters = new SignatureImageTextParameters();
DSSFont font = new DSSJavaFont(Font.SERIF);
font.setSize(16); // Specifies the text size value (the default font size is 12pt)
textParameters.setFont(font);
textParameters.setTextColor(Color.BLUE);
textParameters.setSignerTextPosition(SignerTextPosition.RIGHT);
// Specifies a horizontal alignment of a text with respect to its area
textParameters.setSignerTextHorizontalAlignment(SignerTextHorizontalAlignment.LEFT);
// Specifies a vertical alignment of a text block with respect to a signature field area
textParameters.setSignerTextVerticalAlignment(SignerTextVerticalAlignment.TOP);
imageParameters.setTextParameters(textParameters);
FileDocument fileToSign = new FileDocument("file.pdf");
RemoteDocument fileSign = RemoteDocumentConverter.toRemoteDocument(fileToSign);
DSSDocument toSignDocument = RemoteDocumentConverter.toDSSDocument(fileSign);
byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);
DSSDocument signatureValue = SignHashDocument.signHash(hash);
DSSDocument signedDocument = pdfSignatureService.sign(toSignDocument, DSSUtils.toByteArray(signatureValue), parameters);
save(signedDocument);
Run Code Online (Sandbox Code Playgroud)
****** 哈希签名 ********
// Create common certificate verifier
CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
// Create CAdESService for signature
CAdESService service = new CAdESService(commonCertificateVerifier);
CAdESSignatureParameters parameters = new CAdESSignatureParameters();
DSSPrivateKeyEntry privateKey = getKey("certificate.p12","123456");
// We choose the level of the signature (-B, -T, -LT, -LTA).
parameters.setSignatureLevel(SignatureLevel.CAdES_BASELINE_B);
parameters.setSignaturePackaging(SignaturePackaging.ENVELOPING);
parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
// We set the signing certificate
parameters.setSigningCertificate(privateKey.getCertificate());
// We set the certificate chain
parameters.setCertificateChain(privateKey.getCertificateChain());
SignatureTokenConnection signingToken = new Pkcs12SignatureToken("certificate.p12",
new KeyStore.PasswordProtection("123456".toCharArray()));
convertByteArrayToFile(hashToSign,"filetosign.hash");
FileDocument fileToSign = new FileDocument("filetosign.hash");
RemoteDocument fileSign = RemoteDocumentConverter.toRemoteDocument(fileToSign);
DSSDocument toSignDocument = RemoteDocumentConverter.toDSSDocument(fileSign);
//ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);
ToBeSigned dataToSign = new ToBeSigned(hashToSign);
DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm();
SignatureValue signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
return signedDocument;
Run Code Online (Sandbox Code Playgroud)
****** PDF 错误:************
这是为了回应您问题的原始修订版而写的。
您的代码提到了 PAdES。因此,当您说尝试使用 DSS 签署 PDF 文档时,我假设您指的是集成 PAdES(不是分离的 CAdES 或 XAdES)签名。
创建集成 PDF 签名(如 PAdES)需要首先准备 PDF 以能够携带嵌入签名,即向现有或新签名字段添加签名字典。这个签名字典包含了多种信息,签名时间、签名原因等,同时也是一个占位符,用于后面嵌入CMS签名容器。然后对这个准备好的 PDF(占位符除外)进行哈希处理。
此外,您的代码提到您选择签名的级别 (-B, -T, -LT, -LTA)。
创建 PAdES Baseline LT 和 PAdES Baseline LTA 签名需要准备具有 PAdES Baseline T 签名的 PDF,并根据 T 签名的性质添加其他对象的集合。
如果 eSig DSS 有 PDF 可供准备,它可以为您完成所有这些准备工作。
因此,如果您只想从服务器 A 向 B 发送哈希值,则必须在服务器 A 上使用 eSig DSS 来完成大部分工作,而服务器 B 仅充当返回签名哈希值的哑签名服务或大多数可用于 PAdES 的 CMS 容器。
您是否可以在服务器 A 不知道证书的情况下执行此操作,取决于您是否希望证书详细信息显示在新签名的签名小部件中。创建小部件外观是 PDF 准备步骤的一部分,因此如果您想要这样一个带有证书信息的小部件,服务器 A 需要知道证书,通常甚至在请求签名之前!
那么服务器 A 和 B 之间运行什么样的协议,就由你决定了。您只需SignatureTokenConnection相应地实现即可在 eSig DSS 中的服务器 A 上使用来与服务器 B 进行通信。
现在显示来自两台服务器的代码后,人们可以讨论您的具体方法。
在服务器 A 上,您使用 eSig DSS 准备 PAdES 签名,并在调用返回中嵌入 CMS 签名SignatureValue容器SignHashDocument.signHash:
ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);
SignatureValue signatureValue = SignHashDocument.signHash(dataToSign);
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
Run Code Online (Sandbox Code Playgroud)
即服务器 A 创建 CMS 签名容器,而服务器 B 仅提供签名的哈希值。
除非您知道用于签名的证书并在调用parameters之前将其设置,否则这无法工作service.getDataToSign。
原因是 CMS 容器在容器的未签名字节和(对于 PAdES)签名字节中都包含对该证书的引用。对于未签名字节中的引用,理论上,连同签名字节一起检索证书就足够了,但对于签名字节中的引用,必须事先知道。
或者,您可以尝试在服务器 B 上实现 CMS 容器的完整生成。
但这需要相当大的改变,而且你必须更深入地研究源头PAdESService。您必须执行以下操作,而不是在服务器 A 上引用上面引用的三行:
首先检索 PDF 对象库和 PDF 签名服务
IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
Run Code Online (Sandbox Code Playgroud)
第一次准备 PDF 进行签名并计算文档摘要,
byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);
Run Code Online (Sandbox Code Playgroud)
将此文档摘要发送到后端(服务器 B),后端必须创建并返回一个特殊的 CAdES 签名容器,而不仅仅是裸露的签名字节,
并再次准备 PDF 进行签名并注入此签名容器:
DSSDocument signature = pdfSignatureService.sign(toSignDocument, encodedData, parameters);
Run Code Online (Sandbox Code Playgroud)
以下是使用 eSig DSS 5.8 的概念证明:
在您的服务器 A 上,我们基本上可以使用您现有的代码:
IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
Run Code Online (Sandbox Code Playgroud)
(SplitPAdESSing测试testSplitPAdESGenerationForMehdi)
该方法signHash现在应为给定的文档哈希独立创建 CMS 签名容器,并且该容器应符合 PAdES 要求。eSig DSS 包含提供此功能的方法和类,但它们protected甚至不太可见。因此,对于我们的 POC,我们只需将它们复制到我们的代码中即可。
为简单起见,我使用硬编码 SHA512withRSA 作为签名算法。
因此:
byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);
Run Code Online (Sandbox Code Playgroud)
辅助方法getDataToSign和generateCMSSignedData基本上是从 ; 复制的PAdESService。他们使用padesCMSSignedDataBuilder提供的signHash(而不是成员变量,您也可以将其作为这两个方法的另一个参数):
DSSDocument signature = pdfSignatureService.sign(toSignDocument, encodedData, parameters);
Run Code Online (Sandbox Code Playgroud)
由于可见性有限,类PadesCMSSignedDataBuilder和内容将被复制:PAdESLevelBaselineB
DSSDocument toSignDocument = PDF_DOCUMENT_TO_SIGN;
DSSDocument image = IMAGE_DOCUMENT;
PAdESSignatureParameters parameters = new PAdESSignatureParameters();
parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
parameters.setReason("Preuve de signature");
parameters.setLocation("MAROC");
parameters.setGenerateTBSWithoutCertificate(true);
SignatureImageParameters imageParameters = new SignatureImageParameters();
imageParameters.setPage(1);
imageParameters.setImage(image);
imageParameters.setxAxis(350);
imageParameters.setyAxis(400);
imageParameters.setWidth(200);
imageParameters.setHeight(100);
parameters.setImageParameters(imageParameters);
SignatureImageTextParameters textParameters = new SignatureImageTextParameters();
DSSFont font = new DSSJavaFont(Font.SERIF);
font.setSize(16);
textParameters.setFont(font);
textParameters.setTextColor(Color.BLUE);
textParameters.setSignerTextPosition(SignerTextPosition.RIGHT);
textParameters.setSignerTextHorizontalAlignment(SignerTextHorizontalAlignment.LEFT);
textParameters.setSignerTextVerticalAlignment(SignerTextVerticalAlignment.TOP);
textParameters.setText("TESTING");
imageParameters.setTextParameters(textParameters);
IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);
byte[] signatureValue = signHash(hash);
DSSDocument signedDocument = pdfSignatureService.sign(toSignDocument, signatureValue, parameters);
signedDocument.save(PATH_TO_SAVE_THE_SIGNED_DOCUMENT_TO);
Run Code Online (Sandbox Code Playgroud)
(SplitPAdESSigning帮助程序类)
signHash及其帮助程序不依赖于服务器 A 代码,因此也可以位于服务器 B 上。
| 归档时间: |
|
| 查看次数: |
3676 次 |
| 最近记录: |