Created
September 26, 2020 14:05
-
-
Save HamidOsouli-zz/494f998bb1ec05cdb900466836d3ac43 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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