Skip to content

Instantly share code, notes, and snippets.

@HamidOsouli-zz
Created September 26, 2020 14:05
Show Gist options
  • Save HamidOsouli-zz/494f998bb1ec05cdb900466836d3ac43 to your computer and use it in GitHub Desktop.
Save HamidOsouli-zz/494f998bb1ec05cdb900466836d3ac43 to your computer and use it in GitHub Desktop.
package adanic.signer.rishe.services;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.ExternalBlankSignatureContainer;
import com.itextpdf.signatures.IExternalSignatureContainer;
import com.itextpdf.signatures.PdfPKCS7;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class PadES {
public static final String DEST = "./target/signatures/chapter04/";
public static final String SRC = "/Users/hamid/Documents/Resources/rishe/docker-compose-test/signer/test.pdf";
public static final String TEMP = "./Users/hamid/Documents/Resources/rishe/docker-compose-test/signer/result.pdf";
public static final String KEYSTORE = "./src/test/resources/encryption/ks";
public static final char[] PASSWORD = "password".toCharArray();
public static final String[] RESULT_FILES = new String[] {
"hello_sig_ok.pdf"
};
public static void main(String[] args) throws IOException, GeneralSecurityException {
File file = new File(DEST);
file.mkdirs();
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = ks.aliases().nextElement();
Certificate[] chain = ks.getCertificateChain(alias);
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
PadES app = new PadES();
app.emptySignature(SRC, TEMP, "sig", chain);
app.createSignature(TEMP, DEST + RESULT_FILES[0], "sig", pk, chain);
}
public void emptySignature(String src, String dest, String fieldname, Certificate[] chain)
throws IOException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance
.setPageRect(new Rectangle(36, 748, 200, 100))
.setPageNumber(1)
.setCertificate(chain[0]);
signer.setFieldName(fieldname);
/* ExternalBlankSignatureContainer constructor will create the PdfDictionary for the signature
* information and will insert the /Filter and /SubFilter values into this dictionary.
* It will leave just a blank placeholder for the signature that is to be inserted later.
*/
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite,
PdfName.Adbe_pkcs7_detached);
// Sign the document using an external container.
// 8192 is the size of the empty signature placeholder.
signer.signExternalContainer(external, 8192);
}
public void createSignature(String src, String dest, String fieldName, PrivateKey pk, Certificate[] chain) throws IOException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
try(FileOutputStream os = new FileOutputStream(dest)) {
PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
IExternalSignatureContainer external = new MyExternalSignatureContainer(pk, chain);
// Signs a PDF where space was already reserved. The field must cover the whole document.
signer.signDeferred(signer.getDocument(), fieldName, os, external);
}
}
class MyExternalSignatureContainer implements IExternalSignatureContainer {
protected PrivateKey pk;
protected Certificate[] chain;
public MyExternalSignatureContainer(PrivateKey pk, Certificate[] chain) {
this.pk = pk;
this.chain = chain;
}
public byte[] sign(InputStream is) throws GeneralSecurityException {
try {
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "BC");
String hashAlgorithm = signature.getHashAlgorithm();
BouncyCastleDigest digest = new BouncyCastleDigest();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest, false);
byte hash[] = DigestAlgorithms.digest(is, digest.getMessageDigest(hashAlgorithm));
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, PdfSigner.CryptoStandard.CADES, null, null);
byte[] extSignature = signature.sign(sh);
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, PdfSigner.CryptoStandard.CMS, null, null, null);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public void modifySigningDictionary(PdfDictionary signDic) {
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment