gpt4 book ai didi

java - 使用网络 HSM 和 PDFBox 签署 PDF

转载 作者:行者123 更新时间:2023-11-30 06:07:31 26 4
gpt4 key购买 nike

我尝试以 CreateSignature 示例为起点,并对其进行更改,以使其与我们基于外部网络的 HSM 系统配合使用。

生成的 PDF 文档总是提示“文档已被更改”。我不知道应该用什么来签名。

以下是我的CreateSignatureBase.java中sign()的实现:

@Override
public byte[] sign(InputStream content) throws IOException {

// cannot be done private (interface)
try {

// Certificate chain is acquired at initialization
List<Certificate> certList = new ArrayList<>();
certList.addAll(Arrays.asList(certificateChain));
Store<?> certs = new JcaCertStore(certList);
org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(certificateChain[0].getEncoded());

CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

//HSMSigner is the class that interacts with the network HSM to get the signature.
HSMSigner signer = new HSMSigner();
byte[] input = IOUtil.toByteArray(content);

//SignedHash is a base64-encoded PKCS1 block. see HSMSigner.getSignature() below
final String signedHash = signer.getSignature(input);

ContentSigner sha1Signer = new ContentSigner() {

@Override
public byte[] getSignature() {
return Base64.getDecoder().decode(signedHash);
}

@Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}

@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WITHRSAENCRYPTION");
}
};

gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(cert)));
gen.addCertificates(certs);
CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
CMSSignedData cmsSignedData = gen.generate(msg, true);

byte[] result = cmsSignedData.getEncoded();

return result;

} catch (GeneralSecurityException | CMSException | OperatorCreationException e) {
throw new IOException(e);
}

}

下面是HSMSigner().getSignature()的实现

public String getSignature(byte [] bytes) {


String host = "hsmvip.corp.com";
int port = 9000;
SignClient signClient;
try {
//initialize the sign client
signClient = ///..;
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(bytes);
byte[] outputDigest = messageDigest.digest();

// signature returned by the sign method is a base64-encoded PKCS1 block.
String signature = signClient.sign(Base16.encodeAsString(outputDigest));
signClient.close();
return signature;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}

}

非常感谢任何帮助找出我做错了什么的帮助。

可在 https://file.io/2tVvYO 找到已签名 pdf 的副本

提前致谢!

最佳答案

感谢您的详细回复,我能够按如下方式更新 CreateSignatureBase.sign() 方法以获得所需的结果

CreateSignautreBase.java:sign()

    @Override
public byte[] sign(InputStream content) throws IOException {

// cannot be done private (interface)
try {

// Certificate chain is acquired at initialization
List<Certificate> certList = new ArrayList<>();
certList.addAll(Arrays.asList(certificateChain));
Store<?> certs = new JcaCertStore(certList);
org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(certificateChain[0].getEncoded());

CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

//HSMSigner is the class that interacts with the network HSM to get the signature.
HSMSigner signer = new HSMSigner();
byte[] input = IOUtil.toByteArray(content);

//This is the update over previous code.
//Create a hash of the content and add it to the attribute map
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(input);
Attribute attr = new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(messageDigest.digest())));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);

ContentSigner sha1Signer = new ContentSigner() {
//This is to ensure that signature is created using the right data.
ByteArrayOutputStream stream = new ByteArrayOutputStream();

@Override
public byte[] getSignature() {
//Calling HSM here instead, the stream is the AttributeMap
return Base64.getDecoder().decode(signer.getSignature(stream.toByteArray()));
}
//Perhaps called by BouncyCastle library to provide the content
@Override
public OutputStream getOutputStream() {
return stream;
}

@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WITHRSAENCRYPTION");
}
};

//As per mkl's comment, using the AttributeTable as an input where the table already has a Hashed value of the content.
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));

gen.addSignerInfoGenerator(builder.build(sha1Signer, new X509CertificateHolder(cert)));

gen.addCertificates(certs);
CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
CMSSignedData cmsSignedData = gen.generate(msg, true);

byte[] result = cmsSignedData.getEncoded();

return result;

} catch (GeneralSecurityException | CMSException | OperatorCreationException e) {
throw new IOException(e);
}

}

HSMSigner.getSignature() 保持不变。

关于java - 使用网络 HSM 和 PDFBox 签署 PDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50996721/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com