问题
I am trying to use mobile signature service provider (MSSP) to sign the pdf file.
I used some code below to do. But the signature is invalid with the message "The document has been altered or corrupted since the signatures was applied."
Encode in "APWebService.sign(phoneNumber, messageDisplay, encode)" only accept 44 charracter.
Anyone can help me?
public class MyExternalSignatureContainer implements ExternalSignatureContainer {
protected byte[] sig;
protected Certificate[] chain;
public static final String SRC = "/media/thanhpx1/MEDIA/FileCongVan.pdf";
public static final String TEMP = "/media/thanhpx1/MEDIA/hello_changed.pdf";
public static final String DEST_SIGN = "/media/thanhpx1/MEDIA/signed.pdf";
public MyExternalSignatureContainer(byte[] sig, Certificate[] chain) {
this.sig = sig;
this.chain = chain;
}
public MyExternalSignatureContainer(Certificate[] chain) {
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, java.io.IOException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
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, Certificate[] chain) throws GeneralSecurityException, MalformedURLException, java.io.IOException {
BouncyCastleDigest digest = new BouncyCastleDigest();
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
//hash.length=32
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
//sh.length=77
InputStream shInputStream = new ByteArrayInputStream(sh);
byte[] signedAttributesHash = DigestAlgorithms.digest(shInputStream, digest.getMessageDigest("SHA256"));
//signedAttributesHash.length=32
String encode = com.itextpdf.io.codec.Base64.encodeBytes(signedAttributesHash);
//encode have 44 characters
String phoneNumber = "xxxxxxxxx";
String messageDisplay = "Please sign this document";
//Send to Application Provider WS
String resultSign = APWebService.sign(phoneNumber, messageDisplay, encode);
//resultSign = W5srXKNmRdXNd7uX/QsYhBPet8DOdO9A6F/Ku5ey5JoTatYEJVaEvXB7MjZ3w2W2tEetpZVfc0eFSmMwp/z3TZVX7JvjiN0uCjXgFtCCRr7ffm+jcbp2MEK4hJCCNoHawpjvVV1Qykcg1gerHQDaSSQhtrfJsxOVd0KUIgfIJeBmGMZMGerdz+snH9pe74fMlX+IuEp5Hhk0R6xuwL9vKFxvCVPyv/U6eRmlQmG/wIzr6IBIWET0JDNNgWjmq+jKL70hxZLakZU9Hqu1zKzpkS5jB+0UXMayjBldBuPF1rofgRJKsT8BJttQ8a/YYZr6Sw0X8m8Ah+yPCGTWunRUhA==
byte[] signedHashValue = com.itextpdf.io.codec.Base64.decode(resultSign);
sgn.setExternalDigest(signedHashValue, null, "RSA");
return sgn.getEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
}
public void createSignature(String src, String dest, String fieldname, byte[] hash,
Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException, java.io.IOException {
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, java.io.IOException {
String phoneNumber = "xxxxxxxx";
//Call from Application Provider WS to get certificate
GetCertDto certDto = APWebService.getCertInfo(phoneNumber);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream bytes = new ByteArrayInputStream(Base64.decodeBase64(certDto.getValue()));
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(bytes);
X509Certificate[] certArr = new X509Certificate[1];
certArr[0] = cert;
MyExternalSignatureContainer app = new MyExternalSignatureContainer(certArr);
byte[] hh = app.emptySignature_hash(SRC, TEMP, "sig1", certArr);
byte[] hh_sign = (app.signed_hash(hh, certArr));
app.createSignature(TEMP, DEST_SIGN, "sig1", hh_sign, certArr);
System.out.println("done");
}
@Override
public void modifySigningDictionary(PdfDictionary signDic) {
}
}
来源:https://stackoverflow.com/questions/59497941/itext-signing-pdf-using-external-signature-with-pki-sim