使用密钥库java签名

时间:2017-10-10 08:53:32

标签: java pdf x509certificate keystore sign

我使用keytool创建证书:

keytool -genkeypair -alias sara -keyalg RSA -keysize 2048 -keypass
password -keystore "\Sviluppo\JavaKeyStore\keystore.jks" -storepass
12345678 -validity 360 -dname "cn=Sara, ou=***, o=***, l=Padova,
s=Italia, c=IT"

然后我想用这个证书签署一个pdf,我使用Itextpdf来签署一个pdf。 首先,我从密钥库加载私钥和证书:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
File fileKeyStore = new File(pathKeyStore);
FileInputStream fis = new FileInputStream(fileKeyStore);
keyStore.load(fis, "12345678".toCharArray());
final PrivateKey privateKey = (PrivateKey) keyStore.getKey("sara", "password".toCharArray());
final Certificate certificate = keyStore.getCertificate(certID);

然后我打开文件计算哈希签名:

PdfReader reader = new PdfReader(new RandomAccessFileOrArray(pdfInputPath), null);
OutputStream pdfOutputStream = new FileOutputStream(pdfOutputPath);

PdfStamper stp = PdfStamper.createSignature(reader, pdfOutputStream, '\0', tempPathFile, true)
PdfSignatureAppearance sap = stp.getSignatureAppearance();
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setDate(dateNow);
sap.setCryptoDictionary(dic);
sap.setCrypto(privateKey, keyStore.getCertificateChain("sara"), null, PdfSignatureAppearance.SELF_SIGNED);

HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, (int) (6144 * 2 + 2));
sap.preClose(exc);

然后计算sap.getRangeStream()的哈希值,从密钥库加载证书:

BufferedInputStream bis = new BufferedInputStream(sap.getRangeStream());
MessageDigest digest = MessageDigest.getInstance("SHA-256");
DigestInputStream dis = new DigestInputStream(bis, digest);
byte[] buff = new byte[512];
while (dis.read(buff) != -1) {
  ;
}
dis.close();
dis = null;
byte[] hashToSign= digest.digest();
bis.close();

我使用密钥库的证书签名:

java.security.Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(hashToSign);
byte[] hashSigned = signature.sign();

结束时关闭pdf:

byte[] paddedSig = new byte[6144];
System.arraycopy(hashSigned, 0, paddedSig, 0, hashSigned.length);
PdfDictionary pdfDictionary = new PdfDictionary();
pdfDictionary.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(pdfDictionary);

但签署的pdf无效:“此签名中包含的格式或信息存在错误

问题是什么,证书或签名? 感谢帮助 萨拉

1 个答案:

答案 0 :(得分:0)

&#34;原因是此签名中包含的格式或信息有错误&#34;验证失败消息是您的代码将裸露的PKCS1签名值放在需要完整成熟的CMS签名容器的位置:

您一方面在SELF_SIGNED中使用sap.setCrypto,表示您要创建 adbe.x509.rsa_sha1 SubFilter 签名,另一方面,在您的PdfSignature构造函数中将 SubFilter 设置为 adbe.pkcs7.detached

根本不匹配, adbe.x509.rsa_sha1 使用裸露的PKCS1签名值,而 adbe.pkcs7.detached 使用CMS签名容器。

这应该回答您的问题&#34;问题,证书或签名是什么?&#34; ...

根据评论,您同时在行动第2版的iText副本中找到了解决方案。

请注意,iText签名API同时已经大幅扩展。如果您使用的是iText 5.5.x,则应下载并阅读Bruno Lowagie(iText Software)的白皮书Digital Signatures for PDF Documents

虽然来自 iText in Action,2nd Edition 的代码仍然专注于根据ISO 32000-1:2008签署的签名(SOTA在发布时但不再是), Digital PDF文档的签名侧重于根据PAdES签名,同时已包含在ISO 32000-2:2017中。