Itext pdf 延迟签名导致 pdf 签名无效
Itext pdf deferred signing results in pdf with invalid signature
作为 client/server pdf 签名研究的一部分,我测试了 itext pdf 延迟签名示例。不幸的是,我生成的 pdf 即合并的空签名 pdf 和哈希值的输出显示无效签名。
我的代码片段如下
class MyExternalSignatureContainer implements ExternalSignatureContainer {
protected byte[] sig;
protected Certificate[] chain;
public MyExternalSignatureContainer(byte[] sig,Certificate[] chain) {
this.sig = sig;
this.chain=chain;
}
public byte[] sign(InputStream is)throws GeneralSecurityException {
return sig;
}
public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=10=]');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
Calendar cal = Calendar.getInstance();
cal1=cal;
System.out.println(cal);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
return(sh);
}
public byte[] signed_hash(byte[] hash, PrivateKey pk, Certificate[] chain)throws GeneralSecurityException{
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "SunPKCS11-eToken");
byte[] extSignature = signature.sign(hash);
//return extSignature;
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, cal1, null, null, null, CryptoStandard.CMS);
}
public void createSignature(String src, String dest, String fieldname,byte[] hash, PrivateKey pk, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
ExternalSignatureContainer external = new MyExternalSignatureContainer(hash,chain);
MakeSignature.signDeferred(reader, fieldname, os, external);
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
byte[] hh = app.emptySignature_hash(SRC, TEMP, "sig1", chain);
byte[] hh_sign = (app.signed_hash(hh, pk, chain));
app.createSignature(TEMP, DEST1, "sig1",hh_sign, pk, chain);
}
出了点问题。我想不通。搜索了很多相同的教程。
我正在使用 pkcss11 usb 令牌进行签名
您的体系结构是错误的,因为您在 运行 MakeSignature.signExternalContainer
之后使用了 PdfSignatureAppearance appearance
。 signExternalContainer
和 MakeSignature
中的 signDetached
重载都关闭了底层的 PdfStamper
、PdfSignatureAppearance
和 PdfReader
实例。
因此,当您在方法中执行以下操作时 emptySignature_hash
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
您的 inp
可能不一定包含任何合理的内容。
相反,您应该访问字节范围以登录您的 external
对象,它将检索它作为其 sign
方法的参数。简单地将哈希计算重构到该方法中,并将计算出的哈希存储在该容器的成员中,以便在 emptySignature_hash
.
中检索它
由于您没有分享签名代码的示例结果,我无法确定您的签名是否还存在其他问题。
这是我的错误。
我修改了 emptySignature_hash 方法和 signed_hash 如下,现在它工作正常。
emptySignature_hash 方法 return 仅摘要未验证字节
public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=10=]');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
return hash;
}
public byte[] signed_hash(byte[] hash, PrivateKey pk, Certificate[] chain)throws GeneralSecurityException{
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "SunPKCS11-eToken");
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.sign(sh);
System.out.println(signature.getEncryptionAlgorithm());
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
}
我认为问题是之前我在 emptysignature_hash 方法中 returning getAuthenticatedAttributeBytes 的散列。
并且在 signed_hash() 方法中我将 authenticatedattributebytes 传递给
sgn.getEncodedPKCS7.
作为 client/server pdf 签名研究的一部分,我测试了 itext pdf 延迟签名示例。不幸的是,我生成的 pdf 即合并的空签名 pdf 和哈希值的输出显示无效签名。
我的代码片段如下
class MyExternalSignatureContainer implements ExternalSignatureContainer {
protected byte[] sig;
protected Certificate[] chain;
public MyExternalSignatureContainer(byte[] sig,Certificate[] chain) {
this.sig = sig;
this.chain=chain;
}
public byte[] sign(InputStream is)throws GeneralSecurityException {
return sig;
}
public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=10=]');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
Calendar cal = Calendar.getInstance();
cal1=cal;
System.out.println(cal);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
return(sh);
}
public byte[] signed_hash(byte[] hash, PrivateKey pk, Certificate[] chain)throws GeneralSecurityException{
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "SunPKCS11-eToken");
byte[] extSignature = signature.sign(hash);
//return extSignature;
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, cal1, null, null, null, CryptoStandard.CMS);
}
public void createSignature(String src, String dest, String fieldname,byte[] hash, PrivateKey pk, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
ExternalSignatureContainer external = new MyExternalSignatureContainer(hash,chain);
MakeSignature.signDeferred(reader, fieldname, os, external);
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
byte[] hh = app.emptySignature_hash(SRC, TEMP, "sig1", chain);
byte[] hh_sign = (app.signed_hash(hh, pk, chain));
app.createSignature(TEMP, DEST1, "sig1",hh_sign, pk, chain);
}
出了点问题。我想不通。搜索了很多相同的教程。
我正在使用 pkcss11 usb 令牌进行签名
您的体系结构是错误的,因为您在 运行 MakeSignature.signExternalContainer
之后使用了 PdfSignatureAppearance appearance
。 signExternalContainer
和 MakeSignature
中的 signDetached
重载都关闭了底层的 PdfStamper
、PdfSignatureAppearance
和 PdfReader
实例。
因此,当您在方法中执行以下操作时 emptySignature_hash
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
您的 inp
可能不一定包含任何合理的内容。
相反,您应该访问字节范围以登录您的 external
对象,它将检索它作为其 sign
方法的参数。简单地将哈希计算重构到该方法中,并将计算出的哈希存储在该容器的成员中,以便在 emptySignature_hash
.
由于您没有分享签名代码的示例结果,我无法确定您的签名是否还存在其他问题。
这是我的错误。 我修改了 emptySignature_hash 方法和 signed_hash 如下,现在它工作正常。
emptySignature_hash 方法 return 仅摘要未验证字节
public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=10=]');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
return hash;
}
public byte[] signed_hash(byte[] hash, PrivateKey pk, Certificate[] chain)throws GeneralSecurityException{
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "SunPKCS11-eToken");
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.sign(sh);
System.out.println(signature.getEncryptionAlgorithm());
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
}
我认为问题是之前我在 emptysignature_hash 方法中 returning getAuthenticatedAttributeBytes 的散列。
并且在 signed_hash() 方法中我将 authenticatedattributebytes 传递给 sgn.getEncodedPKCS7.